summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/engine/interpreter')
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/compiler.go3632
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/format.go22
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/interpreter.go4596
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/operations.go2812
-rw-r--r--vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/signature.go767
5 files changed, 0 insertions, 11829 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/compiler.go b/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/compiler.go
deleted file mode 100644
index 4e20e4b2c..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/compiler.go
+++ /dev/null
@@ -1,3632 +0,0 @@
-package interpreter
-
-import (
- "bytes"
- "encoding/binary"
- "fmt"
- "math"
- "strings"
-
- "github.com/tetratelabs/wazero/api"
- "github.com/tetratelabs/wazero/internal/leb128"
- "github.com/tetratelabs/wazero/internal/wasm"
-)
-
-type controlFrameKind byte
-
-const (
- controlFrameKindBlockWithContinuationLabel controlFrameKind = iota
- controlFrameKindBlockWithoutContinuationLabel
- controlFrameKindFunction
- controlFrameKindLoop
- controlFrameKindIfWithElse
- controlFrameKindIfWithoutElse
-)
-
-type (
- controlFrame struct {
- frameID uint32
- // originalStackLenWithoutParam holds the number of values on the stack
- // when Start executing this control frame minus params for the block.
- originalStackLenWithoutParam int
- // originalStackLenWithoutParamUint64 is almost the same as originalStackLenWithoutParam
- // except that it holds the number of values on the stack in uint64.
- originalStackLenWithoutParamUint64 int
- blockType *wasm.FunctionType
- kind controlFrameKind
- }
- controlFrames struct{ frames []controlFrame }
-)
-
-func (c *controlFrame) ensureContinuation() {
- // Make sure that if the frame is block and doesn't have continuation,
- // change the Kind so we can emit the continuation block
- // later when we reach the End instruction of this frame.
- if c.kind == controlFrameKindBlockWithoutContinuationLabel {
- c.kind = controlFrameKindBlockWithContinuationLabel
- }
-}
-
-func (c *controlFrame) asLabel() label {
- switch c.kind {
- case controlFrameKindBlockWithContinuationLabel,
- controlFrameKindBlockWithoutContinuationLabel:
- return newLabel(labelKindContinuation, c.frameID)
- case controlFrameKindLoop:
- return newLabel(labelKindHeader, c.frameID)
- case controlFrameKindFunction:
- return newLabel(labelKindReturn, 0)
- case controlFrameKindIfWithElse,
- controlFrameKindIfWithoutElse:
- return newLabel(labelKindContinuation, c.frameID)
- }
- panic(fmt.Sprintf("unreachable: a bug in interpreterir implementation: %v", c.kind))
-}
-
-func (c *controlFrames) functionFrame() *controlFrame {
- // No need to check stack bound
- // as we can assume that all the operations
- // are valid thanks to validateFunction
- // at module validation phase.
- return &c.frames[0]
-}
-
-func (c *controlFrames) get(n int) *controlFrame {
- // No need to check stack bound
- // as we can assume that all the operations
- // are valid thanks to validateFunction
- // at module validation phase.
- return &c.frames[len(c.frames)-n-1]
-}
-
-func (c *controlFrames) top() *controlFrame {
- // No need to check stack bound
- // as we can assume that all the operations
- // are valid thanks to validateFunction
- // at module validation phase.
- return &c.frames[len(c.frames)-1]
-}
-
-func (c *controlFrames) empty() bool {
- return len(c.frames) == 0
-}
-
-func (c *controlFrames) pop() (frame *controlFrame) {
- // No need to check stack bound
- // as we can assume that all the operations
- // are valid thanks to validateFunction
- // at module validation phase.
- frame = c.top()
- c.frames = c.frames[:len(c.frames)-1]
- return
-}
-
-func (c *controlFrames) push(frame controlFrame) {
- c.frames = append(c.frames, frame)
-}
-
-func (c *compiler) initializeStack() {
- // Reuse the existing slice.
- c.localIndexToStackHeightInUint64 = c.localIndexToStackHeightInUint64[:0]
- var current int
- for _, lt := range c.sig.Params {
- c.localIndexToStackHeightInUint64 = append(c.localIndexToStackHeightInUint64, current)
- if lt == wasm.ValueTypeV128 {
- current++
- }
- current++
- }
-
- if c.callFrameStackSizeInUint64 > 0 {
- // We reserve the stack slots for result values below the return call frame slots.
- if diff := c.sig.ResultNumInUint64 - c.sig.ParamNumInUint64; diff > 0 {
- current += diff
- }
- }
-
- // Non-func param locals Start after the return call frame.
- current += c.callFrameStackSizeInUint64
-
- for _, lt := range c.localTypes {
- c.localIndexToStackHeightInUint64 = append(c.localIndexToStackHeightInUint64, current)
- if lt == wasm.ValueTypeV128 {
- current++
- }
- current++
- }
-
- // Push function arguments.
- for _, t := range c.sig.Params {
- c.stackPush(wasmValueTypeTounsignedType(t))
- }
-
- if c.callFrameStackSizeInUint64 > 0 {
- // Reserve the stack slots for results.
- for i := 0; i < c.sig.ResultNumInUint64-c.sig.ParamNumInUint64; i++ {
- c.stackPush(unsignedTypeI64)
- }
-
- // Reserve the stack slots for call frame.
- for i := 0; i < c.callFrameStackSizeInUint64; i++ {
- c.stackPush(unsignedTypeI64)
- }
- }
-}
-
-// compiler is in charge of lowering raw Wasm function body to get compilationResult.
-// This is created per *wasm.Module and reused for all functions in it to reduce memory allocations.
-type compiler struct {
- module *wasm.Module
- enabledFeatures api.CoreFeatures
- callFrameStackSizeInUint64 int
- stack []unsignedType
- // stackLenInUint64 is the length of the stack in uint64.
- stackLenInUint64 int
- currentFrameID uint32
- controlFrames controlFrames
- unreachableState struct {
- on bool
- depth int
- }
- pc, currentOpPC uint64
- result compilationResult
-
- // body holds the code for the function's body where Wasm instructions are stored.
- body []byte
- // sig is the function type of the target function.
- sig *wasm.FunctionType
- // localTypes holds the target function locals' value types except function params.
- localTypes []wasm.ValueType
- // localIndexToStackHeightInUint64 maps the local index (starting with function params) to the stack height
- // where the local is places. This is the necessary mapping for functions who contain vector type locals.
- localIndexToStackHeightInUint64 []int
-
- // types hold all the function types in the module where the targe function exists.
- types []wasm.FunctionType
- // funcs holds the type indexes for all declared functions in the module where the target function exists.
- funcs []uint32
- // globals holds the global types for all declared globals in the module where the target function exists.
- globals []wasm.GlobalType
-
- // needSourceOffset is true if this module requires DWARF based stack trace.
- needSourceOffset bool
- // bodyOffsetInCodeSection is the offset of the body of this function in the original Wasm binary's code section.
- bodyOffsetInCodeSection uint64
-
- ensureTermination bool
- // Pre-allocated bytes.Reader to be used in various places.
- br *bytes.Reader
- funcTypeToSigs funcTypeToIRSignatures
-
- next int
-}
-
-//lint:ignore U1000 for debugging only.
-func (c *compiler) stackDump() string {
- strs := make([]string, 0, len(c.stack))
- for _, s := range c.stack {
- strs = append(strs, s.String())
- }
- return "[" + strings.Join(strs, ", ") + "]"
-}
-
-func (c *compiler) markUnreachable() {
- c.unreachableState.on = true
-}
-
-func (c *compiler) resetUnreachable() {
- c.unreachableState.on = false
-}
-
-// memoryType is the type of memory in a compiled module.
-type memoryType byte
-
-const (
- // memoryTypeNone indicates there is no memory.
- memoryTypeNone memoryType = iota
- // memoryTypeStandard indicates there is a non-shared memory.
- memoryTypeStandard
- // memoryTypeShared indicates there is a shared memory.
- memoryTypeShared
-)
-
-type compilationResult struct {
- // Operations holds interpreterir operations compiled from Wasm instructions in a Wasm function.
- Operations []unionOperation
-
- // IROperationSourceOffsetsInWasmBinary is index-correlated with Operation and maps each operation to the corresponding source instruction's
- // offset in the original WebAssembly binary.
- // Non nil only when the given Wasm module has the DWARF section.
- IROperationSourceOffsetsInWasmBinary []uint64
-
- // LabelCallers maps label to the number of callers to that label.
- // Here "callers" means that the call-sites which jumps to the label with br, br_if or br_table
- // instructions.
- //
- // Note: zero possible and allowed in wasm. e.g.
- //
- // (block
- // (br 0)
- // (block i32.const 1111)
- // )
- //
- // This example the label corresponding to `(block i32.const 1111)` is never be reached at runtime because `br 0` exits the function before we reach there
- LabelCallers map[label]uint32
- // UsesMemory is true if this function might use memory.
- UsesMemory bool
-
- // The following fields are per-module values, not per-function.
-
- // Globals holds all the declarations of globals in the module from which this function is compiled.
- Globals []wasm.GlobalType
- // Functions holds all the declarations of function in the module from which this function is compiled, including itself.
- Functions []wasm.Index
- // Types holds all the types in the module from which this function is compiled.
- Types []wasm.FunctionType
- // Memory indicates the type of memory of the module.
- Memory memoryType
- // HasTable is true if the module from which this function is compiled has table declaration.
- HasTable bool
- // HasDataInstances is true if the module has data instances which might be used by memory.init or data.drop instructions.
- HasDataInstances bool
- // HasDataInstances is true if the module has element instances which might be used by table.init or elem.drop instructions.
- HasElementInstances bool
-}
-
-// newCompiler returns the new *compiler for the given parameters.
-// Use compiler.Next function to get compilation result per function.
-func newCompiler(enabledFeatures api.CoreFeatures, callFrameStackSizeInUint64 int, module *wasm.Module, ensureTermination bool) (*compiler, error) {
- functions, globals, mem, tables, err := module.AllDeclarations()
- if err != nil {
- return nil, err
- }
-
- hasTable, hasDataInstances, hasElementInstances := len(tables) > 0,
- len(module.DataSection) > 0, len(module.ElementSection) > 0
-
- var mt memoryType
- switch {
- case mem == nil:
- mt = memoryTypeNone
- case mem.IsShared:
- mt = memoryTypeShared
- default:
- mt = memoryTypeStandard
- }
-
- types := module.TypeSection
-
- c := &compiler{
- module: module,
- enabledFeatures: enabledFeatures,
- controlFrames: controlFrames{},
- callFrameStackSizeInUint64: callFrameStackSizeInUint64,
- result: compilationResult{
- Globals: globals,
- Functions: functions,
- Types: types,
- Memory: mt,
- HasTable: hasTable,
- HasDataInstances: hasDataInstances,
- HasElementInstances: hasElementInstances,
- LabelCallers: map[label]uint32{},
- },
- globals: globals,
- funcs: functions,
- types: types,
- ensureTermination: ensureTermination,
- br: bytes.NewReader(nil),
- funcTypeToSigs: funcTypeToIRSignatures{
- indirectCalls: make([]*signature, len(types)),
- directCalls: make([]*signature, len(types)),
- wasmTypes: types,
- },
- needSourceOffset: module.DWARFLines != nil,
- }
- return c, nil
-}
-
-// Next returns the next compilationResult for this compiler.
-func (c *compiler) Next() (*compilationResult, error) {
- funcIndex := c.next
- code := &c.module.CodeSection[funcIndex]
- sig := &c.types[c.module.FunctionSection[funcIndex]]
-
- // Reset the previous result.
- c.result.Operations = c.result.Operations[:0]
- c.result.IROperationSourceOffsetsInWasmBinary = c.result.IROperationSourceOffsetsInWasmBinary[:0]
- c.result.UsesMemory = false
- // Clears the existing entries in LabelCallers.
- for frameID := uint32(0); frameID <= c.currentFrameID; frameID++ {
- for k := labelKind(0); k < labelKindNum; k++ {
- delete(c.result.LabelCallers, newLabel(k, frameID))
- }
- }
- // Reset the previous states.
- c.pc = 0
- c.currentOpPC = 0
- c.currentFrameID = 0
- c.stackLenInUint64 = 0
- c.unreachableState.on, c.unreachableState.depth = false, 0
-
- if err := c.compile(sig, code.Body, code.LocalTypes, code.BodyOffsetInCodeSection); err != nil {
- return nil, err
- }
- c.next++
- return &c.result, nil
-}
-
-// Compile lowers given function instance into interpreterir operations
-// so that the resulting operations can be consumed by the interpreter
-// or the compiler compilation engine.
-func (c *compiler) compile(sig *wasm.FunctionType, body []byte, localTypes []wasm.ValueType, bodyOffsetInCodeSection uint64) error {
- // Set function specific fields.
- c.body = body
- c.localTypes = localTypes
- c.sig = sig
- c.bodyOffsetInCodeSection = bodyOffsetInCodeSection
-
- // Reuses the underlying slices.
- c.stack = c.stack[:0]
- c.controlFrames.frames = c.controlFrames.frames[:0]
-
- c.initializeStack()
-
- // Emit const expressions for locals.
- // Note that here we don't take function arguments
- // into account, meaning that callers must push
- // arguments before entering into the function body.
- for _, t := range c.localTypes {
- c.emitDefaultValue(t)
- }
-
- // Insert the function control frame.
- c.controlFrames.push(controlFrame{
- frameID: c.nextFrameID(),
- blockType: c.sig,
- kind: controlFrameKindFunction,
- })
-
- // Now, enter the function body.
- for !c.controlFrames.empty() && c.pc < uint64(len(c.body)) {
- if err := c.handleInstruction(); err != nil {
- return fmt.Errorf("handling instruction: %w", err)
- }
- }
- return nil
-}
-
-// Translate the current Wasm instruction to interpreterir's operations,
-// and emit the results into c.results.
-func (c *compiler) handleInstruction() error {
- op := c.body[c.pc]
- c.currentOpPC = c.pc
- if false {
- var instName string
- if op == wasm.OpcodeVecPrefix {
- instName = wasm.VectorInstructionName(c.body[c.pc+1])
- } else if op == wasm.OpcodeAtomicPrefix {
- instName = wasm.AtomicInstructionName(c.body[c.pc+1])
- } else if op == wasm.OpcodeMiscPrefix {
- instName = wasm.MiscInstructionName(c.body[c.pc+1])
- } else {
- instName = wasm.InstructionName(op)
- }
- fmt.Printf("handling %s, unreachable_state(on=%v,depth=%d), stack=%v\n",
- instName, c.unreachableState.on, c.unreachableState.depth, c.stack,
- )
- }
-
- var peekValueType unsignedType
- if len(c.stack) > 0 {
- peekValueType = c.stackPeek()
- }
-
- // Modify the stack according the current instruction.
- // Note that some instructions will read "index" in
- // applyToStack and advance c.pc inside the function.
- index, err := c.applyToStack(op)
- if err != nil {
- return fmt.Errorf("apply stack failed for %s: %w", wasm.InstructionName(op), err)
- }
- // Now we handle each instruction, and
- // emit the corresponding interpreterir operations to the results.
-operatorSwitch:
- switch op {
- case wasm.OpcodeUnreachable:
- c.emit(newOperationUnreachable())
- c.markUnreachable()
- case wasm.OpcodeNop:
- // Nop is noop!
- case wasm.OpcodeBlock:
- c.br.Reset(c.body[c.pc+1:])
- bt, num, err := wasm.DecodeBlockType(c.types, c.br, c.enabledFeatures)
- if err != nil {
- return fmt.Errorf("reading block type for block instruction: %w", err)
- }
- c.pc += num
-
- if c.unreachableState.on {
- // If it is currently in unreachable,
- // just remove the entire block.
- c.unreachableState.depth++
- break operatorSwitch
- }
-
- // Create a new frame -- entering this block.
- frame := controlFrame{
- frameID: c.nextFrameID(),
- originalStackLenWithoutParam: len(c.stack) - len(bt.Params),
- originalStackLenWithoutParamUint64: c.stackLenInUint64 - bt.ParamNumInUint64,
- kind: controlFrameKindBlockWithoutContinuationLabel,
- blockType: bt,
- }
- c.controlFrames.push(frame)
-
- case wasm.OpcodeLoop:
- c.br.Reset(c.body[c.pc+1:])
- bt, num, err := wasm.DecodeBlockType(c.types, c.br, c.enabledFeatures)
- if err != nil {
- return fmt.Errorf("reading block type for loop instruction: %w", err)
- }
- c.pc += num
-
- if c.unreachableState.on {
- // If it is currently in unreachable,
- // just remove the entire block.
- c.unreachableState.depth++
- break operatorSwitch
- }
-
- // Create a new frame -- entering loop.
- frame := controlFrame{
- frameID: c.nextFrameID(),
- originalStackLenWithoutParam: len(c.stack) - len(bt.Params),
- originalStackLenWithoutParamUint64: c.stackLenInUint64 - bt.ParamNumInUint64,
- kind: controlFrameKindLoop,
- blockType: bt,
- }
- c.controlFrames.push(frame)
-
- // Prep labels for inside and the continuation of this loop.
- loopLabel := newLabel(labelKindHeader, frame.frameID)
- c.result.LabelCallers[loopLabel]++
-
- // Emit the branch operation to enter inside the loop.
- c.emit(newOperationBr(loopLabel))
- c.emit(newOperationLabel(loopLabel))
-
- // Insert the exit code check on the loop header, which is the only necessary point in the function body
- // to prevent infinite loop.
- //
- // Note that this is a little aggressive: this checks the exit code regardless the loop header is actually
- // the loop. In other words, this checks even when no br/br_if/br_table instructions jumping to this loop
- // exist. However, in reality, that shouldn't be an issue since such "noop" loop header will highly likely be
- // optimized out by almost all guest language compilers which have the control flow optimization passes.
- if c.ensureTermination {
- c.emit(newOperationBuiltinFunctionCheckExitCode())
- }
- case wasm.OpcodeIf:
- c.br.Reset(c.body[c.pc+1:])
- bt, num, err := wasm.DecodeBlockType(c.types, c.br, c.enabledFeatures)
- if err != nil {
- return fmt.Errorf("reading block type for if instruction: %w", err)
- }
- c.pc += num
-
- if c.unreachableState.on {
- // If it is currently in unreachable,
- // just remove the entire block.
- c.unreachableState.depth++
- break operatorSwitch
- }
-
- // Create a new frame -- entering if.
- frame := controlFrame{
- frameID: c.nextFrameID(),
- originalStackLenWithoutParam: len(c.stack) - len(bt.Params),
- originalStackLenWithoutParamUint64: c.stackLenInUint64 - bt.ParamNumInUint64,
- // Note this will be set to controlFrameKindIfWithElse
- // when else opcode found later.
- kind: controlFrameKindIfWithoutElse,
- blockType: bt,
- }
- c.controlFrames.push(frame)
-
- // Prep labels for if and else of this if.
- thenLabel := newLabel(labelKindHeader, frame.frameID)
- elseLabel := newLabel(labelKindElse, frame.frameID)
- c.result.LabelCallers[thenLabel]++
- c.result.LabelCallers[elseLabel]++
-
- // Emit the branch operation to enter the then block.
- c.emit(newOperationBrIf(thenLabel, elseLabel, nopinclusiveRange))
- c.emit(newOperationLabel(thenLabel))
- case wasm.OpcodeElse:
- frame := c.controlFrames.top()
- if c.unreachableState.on && c.unreachableState.depth > 0 {
- // If it is currently in unreachable, and the nested if,
- // just remove the entire else block.
- break operatorSwitch
- } else if c.unreachableState.on {
- // If it is currently in unreachable, and the non-nested if,
- // reset the stack so we can correctly handle the else block.
- top := c.controlFrames.top()
- c.stackSwitchAt(top)
- top.kind = controlFrameKindIfWithElse
-
- // Re-push the parameters to the if block so that else block can use them.
- for _, t := range frame.blockType.Params {
- c.stackPush(wasmValueTypeTounsignedType(t))
- }
-
- // We are no longer unreachable in else frame,
- // so emit the correct label, and reset the unreachable state.
- elseLabel := newLabel(labelKindElse, frame.frameID)
- c.resetUnreachable()
- c.emit(
- newOperationLabel(elseLabel),
- )
- break operatorSwitch
- }
-
- // Change the Kind of this If block, indicating that
- // the if has else block.
- frame.kind = controlFrameKindIfWithElse
-
- // We need to reset the stack so that
- // the values pushed inside the then block
- // do not affect the else block.
- dropOp := newOperationDrop(c.getFrameDropRange(frame, false))
-
- // Reset the stack manipulated by the then block, and re-push the block param types to the stack.
-
- c.stackSwitchAt(frame)
- for _, t := range frame.blockType.Params {
- c.stackPush(wasmValueTypeTounsignedType(t))
- }
-
- // Prep labels for else and the continuation of this if block.
- elseLabel := newLabel(labelKindElse, frame.frameID)
- continuationLabel := newLabel(labelKindContinuation, frame.frameID)
- c.result.LabelCallers[continuationLabel]++
-
- // Emit the instructions for exiting the if loop,
- // and then the initiation of else block.
- c.emit(dropOp)
- // Jump to the continuation of this block.
- c.emit(newOperationBr(continuationLabel))
- // Initiate the else block.
- c.emit(newOperationLabel(elseLabel))
- case wasm.OpcodeEnd:
- if c.unreachableState.on && c.unreachableState.depth > 0 {
- c.unreachableState.depth--
- break operatorSwitch
- } else if c.unreachableState.on {
- c.resetUnreachable()
-
- frame := c.controlFrames.pop()
- if c.controlFrames.empty() {
- return nil
- }
-
- c.stackSwitchAt(frame)
- for _, t := range frame.blockType.Results {
- c.stackPush(wasmValueTypeTounsignedType(t))
- }
-
- continuationLabel := newLabel(labelKindContinuation, frame.frameID)
- if frame.kind == controlFrameKindIfWithoutElse {
- // Emit the else label.
- elseLabel := newLabel(labelKindElse, frame.frameID)
- c.result.LabelCallers[continuationLabel]++
- c.emit(newOperationLabel(elseLabel))
- c.emit(newOperationBr(continuationLabel))
- c.emit(newOperationLabel(continuationLabel))
- } else {
- c.emit(
- newOperationLabel(continuationLabel),
- )
- }
-
- break operatorSwitch
- }
-
- frame := c.controlFrames.pop()
-
- // We need to reset the stack so that
- // the values pushed inside the block.
- dropOp := newOperationDrop(c.getFrameDropRange(frame, true))
- c.stackSwitchAt(frame)
-
- // Push the result types onto the stack.
- for _, t := range frame.blockType.Results {
- c.stackPush(wasmValueTypeTounsignedType(t))
- }
-
- // Emit the instructions according to the Kind of the current control frame.
- switch frame.kind {
- case controlFrameKindFunction:
- if !c.controlFrames.empty() {
- // Should never happen. If so, there's a bug in the translation.
- panic("bug: found more function control frames")
- }
- // Return from function.
- c.emit(dropOp)
- c.emit(newOperationBr(newLabel(labelKindReturn, 0)))
- case controlFrameKindIfWithoutElse:
- // This case we have to emit "empty" else label.
- elseLabel := newLabel(labelKindElse, frame.frameID)
- continuationLabel := newLabel(labelKindContinuation, frame.frameID)
- c.result.LabelCallers[continuationLabel] += 2
- c.emit(dropOp)
- c.emit(newOperationBr(continuationLabel))
- // Emit the else which soon branches into the continuation.
- c.emit(newOperationLabel(elseLabel))
- c.emit(newOperationBr(continuationLabel))
- // Initiate the continuation.
- c.emit(newOperationLabel(continuationLabel))
- case controlFrameKindBlockWithContinuationLabel,
- controlFrameKindIfWithElse:
- continuationLabel := newLabel(labelKindContinuation, frame.frameID)
- c.result.LabelCallers[continuationLabel]++
- c.emit(dropOp)
- c.emit(newOperationBr(continuationLabel))
- c.emit(newOperationLabel(continuationLabel))
- case controlFrameKindLoop, controlFrameKindBlockWithoutContinuationLabel:
- c.emit(
- dropOp,
- )
- default:
- // Should never happen. If so, there's a bug in the translation.
- panic(fmt.Errorf("bug: invalid control frame Kind: 0x%x", frame.kind))
- }
-
- case wasm.OpcodeBr:
- targetIndex, n, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("read the target for br_if: %w", err)
- }
- c.pc += n
-
- if c.unreachableState.on {
- // If it is currently in unreachable, br is no-op.
- break operatorSwitch
- }
-
- targetFrame := c.controlFrames.get(int(targetIndex))
- targetFrame.ensureContinuation()
- dropOp := newOperationDrop(c.getFrameDropRange(targetFrame, false))
- targetID := targetFrame.asLabel()
- c.result.LabelCallers[targetID]++
- c.emit(dropOp)
- c.emit(newOperationBr(targetID))
- // Br operation is stack-polymorphic, and mark the state as unreachable.
- // That means subsequent instructions in the current control frame are "unreachable"
- // and can be safely removed.
- c.markUnreachable()
- case wasm.OpcodeBrIf:
- targetIndex, n, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("read the target for br_if: %w", err)
- }
- c.pc += n
-
- if c.unreachableState.on {
- // If it is currently in unreachable, br-if is no-op.
- break operatorSwitch
- }
-
- targetFrame := c.controlFrames.get(int(targetIndex))
- targetFrame.ensureContinuation()
- drop := c.getFrameDropRange(targetFrame, false)
- target := targetFrame.asLabel()
- c.result.LabelCallers[target]++
-
- continuationLabel := newLabel(labelKindHeader, c.nextFrameID())
- c.result.LabelCallers[continuationLabel]++
- c.emit(newOperationBrIf(target, continuationLabel, drop))
- // Start emitting else block operations.
- c.emit(newOperationLabel(continuationLabel))
- case wasm.OpcodeBrTable:
- c.br.Reset(c.body[c.pc+1:])
- r := c.br
- numTargets, n, err := leb128.DecodeUint32(r)
- if err != nil {
- return fmt.Errorf("error reading number of targets in br_table: %w", err)
- }
- c.pc += n
-
- if c.unreachableState.on {
- // If it is currently in unreachable, br_table is no-op.
- // But before proceeding to the next instruction, we must advance the pc
- // according to the number of br_table targets.
- for i := uint32(0); i <= numTargets; i++ { // inclusive as we also need to read the index of default target.
- _, n, err := leb128.DecodeUint32(r)
- if err != nil {
- return fmt.Errorf("error reading target %d in br_table: %w", i, err)
- }
- c.pc += n
- }
- break operatorSwitch
- }
-
- // Read the branch targets.
- s := numTargets * 2
- targetLabels := make([]uint64, 2+s) // (label, inclusiveRange) * (default+numTargets)
- for i := uint32(0); i < s; i += 2 {
- l, n, err := leb128.DecodeUint32(r)
- if err != nil {
- return fmt.Errorf("error reading target %d in br_table: %w", i, err)
- }
- c.pc += n
- targetFrame := c.controlFrames.get(int(l))
- targetFrame.ensureContinuation()
- drop := c.getFrameDropRange(targetFrame, false)
- targetLabel := targetFrame.asLabel()
- targetLabels[i] = uint64(targetLabel)
- targetLabels[i+1] = drop.AsU64()
- c.result.LabelCallers[targetLabel]++
- }
-
- // Prep default target control frame.
- l, n, err := leb128.DecodeUint32(r)
- if err != nil {
- return fmt.Errorf("error reading default target of br_table: %w", err)
- }
- c.pc += n
- defaultTargetFrame := c.controlFrames.get(int(l))
- defaultTargetFrame.ensureContinuation()
- defaultTargetDrop := c.getFrameDropRange(defaultTargetFrame, false)
- defaultLabel := defaultTargetFrame.asLabel()
- c.result.LabelCallers[defaultLabel]++
- targetLabels[s] = uint64(defaultLabel)
- targetLabels[s+1] = defaultTargetDrop.AsU64()
- c.emit(newOperationBrTable(targetLabels))
-
- // br_table operation is stack-polymorphic, and mark the state as unreachable.
- // That means subsequent instructions in the current control frame are "unreachable"
- // and can be safely removed.
- c.markUnreachable()
- case wasm.OpcodeReturn:
- functionFrame := c.controlFrames.functionFrame()
- dropOp := newOperationDrop(c.getFrameDropRange(functionFrame, false))
-
- // Cleanup the stack and then jmp to function frame's continuation (meaning return).
- c.emit(dropOp)
- c.emit(newOperationBr(functionFrame.asLabel()))
-
- // Return operation is stack-polymorphic, and mark the state as unreachable.
- // That means subsequent instructions in the current control frame are "unreachable"
- // and can be safely removed.
- c.markUnreachable()
- case wasm.OpcodeCall:
- c.emit(
- newOperationCall(index),
- )
- case wasm.OpcodeCallIndirect:
- typeIndex := index
- tableIndex, n, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("read target for br_table: %w", err)
- }
- c.pc += n
- c.emit(
- newOperationCallIndirect(typeIndex, tableIndex),
- )
- case wasm.OpcodeDrop:
- r := inclusiveRange{Start: 0, End: 0}
- if peekValueType == unsignedTypeV128 {
- // inclusiveRange is the range in uint64 representation, so dropping a vector value on top
- // should be translated as drop [0..1] inclusively.
- r.End++
- }
- c.emit(newOperationDrop(r))
- case wasm.OpcodeSelect:
- // If it is on the unreachable state, ignore the instruction.
- if c.unreachableState.on {
- break operatorSwitch
- }
- isTargetVector := c.stackPeek() == unsignedTypeV128
- c.emit(
- newOperationSelect(isTargetVector),
- )
- case wasm.OpcodeTypedSelect:
- // Skips two bytes: vector size fixed to 1, and the value type for select.
- c.pc += 2
- // If it is on the unreachable state, ignore the instruction.
- if c.unreachableState.on {
- break operatorSwitch
- }
- // Typed select is semantically equivalent to select at runtime.
- isTargetVector := c.stackPeek() == unsignedTypeV128
- c.emit(
- newOperationSelect(isTargetVector),
- )
- case wasm.OpcodeLocalGet:
- depth := c.localDepth(index)
- if isVector := c.localType(index) == wasm.ValueTypeV128; !isVector {
- c.emit(
- // -1 because we already manipulated the stack before
- // called localDepth ^^.
- newOperationPick(depth-1, isVector),
- )
- } else {
- c.emit(
- // -2 because we already manipulated the stack before
- // called localDepth ^^.
- newOperationPick(depth-2, isVector),
- )
- }
- case wasm.OpcodeLocalSet:
- depth := c.localDepth(index)
-
- isVector := c.localType(index) == wasm.ValueTypeV128
- if isVector {
- c.emit(
- // +2 because we already popped the operands for this operation from the c.stack before
- // called localDepth ^^,
- newOperationSet(depth+2, isVector),
- )
- } else {
- c.emit(
- // +1 because we already popped the operands for this operation from the c.stack before
- // called localDepth ^^,
- newOperationSet(depth+1, isVector),
- )
- }
- case wasm.OpcodeLocalTee:
- depth := c.localDepth(index)
- isVector := c.localType(index) == wasm.ValueTypeV128
- if isVector {
- c.emit(newOperationPick(1, isVector))
- c.emit(newOperationSet(depth+2, isVector))
- } else {
- c.emit(
- newOperationPick(0, isVector))
- c.emit(newOperationSet(depth+1, isVector))
- }
- case wasm.OpcodeGlobalGet:
- c.emit(
- newOperationGlobalGet(index),
- )
- case wasm.OpcodeGlobalSet:
- c.emit(
- newOperationGlobalSet(index),
- )
- case wasm.OpcodeI32Load:
- imm, err := c.readMemoryArg(wasm.OpcodeI32LoadName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad(unsignedTypeI32, imm))
- case wasm.OpcodeI64Load:
- imm, err := c.readMemoryArg(wasm.OpcodeI64LoadName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad(unsignedTypeI64, imm))
- case wasm.OpcodeF32Load:
- imm, err := c.readMemoryArg(wasm.OpcodeF32LoadName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad(unsignedTypeF32, imm))
- case wasm.OpcodeF64Load:
- imm, err := c.readMemoryArg(wasm.OpcodeF64LoadName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad(unsignedTypeF64, imm))
- case wasm.OpcodeI32Load8S:
- imm, err := c.readMemoryArg(wasm.OpcodeI32Load8SName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad8(signedInt32, imm))
- case wasm.OpcodeI32Load8U:
- imm, err := c.readMemoryArg(wasm.OpcodeI32Load8UName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad8(signedUint32, imm))
- case wasm.OpcodeI32Load16S:
- imm, err := c.readMemoryArg(wasm.OpcodeI32Load16SName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad16(signedInt32, imm))
- case wasm.OpcodeI32Load16U:
- imm, err := c.readMemoryArg(wasm.OpcodeI32Load16UName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad16(signedUint32, imm))
- case wasm.OpcodeI64Load8S:
- imm, err := c.readMemoryArg(wasm.OpcodeI64Load8SName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad8(signedInt64, imm))
- case wasm.OpcodeI64Load8U:
- imm, err := c.readMemoryArg(wasm.OpcodeI64Load8UName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad8(signedUint64, imm))
- case wasm.OpcodeI64Load16S:
- imm, err := c.readMemoryArg(wasm.OpcodeI64Load16SName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad16(signedInt64, imm))
- case wasm.OpcodeI64Load16U:
- imm, err := c.readMemoryArg(wasm.OpcodeI64Load16UName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad16(signedUint64, imm))
- case wasm.OpcodeI64Load32S:
- imm, err := c.readMemoryArg(wasm.OpcodeI64Load32SName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad32(true, imm))
- case wasm.OpcodeI64Load32U:
- imm, err := c.readMemoryArg(wasm.OpcodeI64Load32UName)
- if err != nil {
- return err
- }
- c.emit(newOperationLoad32(false, imm))
- case wasm.OpcodeI32Store:
- imm, err := c.readMemoryArg(wasm.OpcodeI32StoreName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationStore(unsignedTypeI32, imm),
- )
- case wasm.OpcodeI64Store:
- imm, err := c.readMemoryArg(wasm.OpcodeI64StoreName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationStore(unsignedTypeI64, imm),
- )
- case wasm.OpcodeF32Store:
- imm, err := c.readMemoryArg(wasm.OpcodeF32StoreName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationStore(unsignedTypeF32, imm),
- )
- case wasm.OpcodeF64Store:
- imm, err := c.readMemoryArg(wasm.OpcodeF64StoreName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationStore(unsignedTypeF64, imm),
- )
- case wasm.OpcodeI32Store8:
- imm, err := c.readMemoryArg(wasm.OpcodeI32Store8Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationStore8(imm),
- )
- case wasm.OpcodeI32Store16:
- imm, err := c.readMemoryArg(wasm.OpcodeI32Store16Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationStore16(imm),
- )
- case wasm.OpcodeI64Store8:
- imm, err := c.readMemoryArg(wasm.OpcodeI64Store8Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationStore8(imm),
- )
- case wasm.OpcodeI64Store16:
- imm, err := c.readMemoryArg(wasm.OpcodeI64Store16Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationStore16(imm),
- )
- case wasm.OpcodeI64Store32:
- imm, err := c.readMemoryArg(wasm.OpcodeI64Store32Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationStore32(imm),
- )
- case wasm.OpcodeMemorySize:
- c.result.UsesMemory = true
- c.pc++ // Skip the reserved one byte.
- c.emit(
- newOperationMemorySize(),
- )
- case wasm.OpcodeMemoryGrow:
- c.result.UsesMemory = true
- c.pc++ // Skip the reserved one byte.
- c.emit(
- newOperationMemoryGrow(),
- )
- case wasm.OpcodeI32Const:
- val, num, err := leb128.LoadInt32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- c.emit(
- newOperationConstI32(uint32(val)),
- )
- case wasm.OpcodeI64Const:
- val, num, err := leb128.LoadInt64(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i64.const value: %v", err)
- }
- c.pc += num
- c.emit(
- newOperationConstI64(uint64(val)),
- )
- case wasm.OpcodeF32Const:
- v := math.Float32frombits(binary.LittleEndian.Uint32(c.body[c.pc+1:]))
- c.pc += 4
- c.emit(
- newOperationConstF32(v),
- )
- case wasm.OpcodeF64Const:
- v := math.Float64frombits(binary.LittleEndian.Uint64(c.body[c.pc+1:]))
- c.pc += 8
- c.emit(
- newOperationConstF64(v),
- )
- case wasm.OpcodeI32Eqz:
- c.emit(
- newOperationEqz(unsignedInt32),
- )
- case wasm.OpcodeI32Eq:
- c.emit(
- newOperationEq(unsignedTypeI32),
- )
- case wasm.OpcodeI32Ne:
- c.emit(
- newOperationNe(unsignedTypeI32),
- )
- case wasm.OpcodeI32LtS:
- c.emit(
- newOperationLt(signedTypeInt32),
- )
- case wasm.OpcodeI32LtU:
- c.emit(
- newOperationLt(signedTypeUint32),
- )
- case wasm.OpcodeI32GtS:
- c.emit(
- newOperationGt(signedTypeInt32),
- )
- case wasm.OpcodeI32GtU:
- c.emit(
- newOperationGt(signedTypeUint32),
- )
- case wasm.OpcodeI32LeS:
- c.emit(
- newOperationLe(signedTypeInt32),
- )
- case wasm.OpcodeI32LeU:
- c.emit(
- newOperationLe(signedTypeUint32),
- )
- case wasm.OpcodeI32GeS:
- c.emit(
- newOperationGe(signedTypeInt32),
- )
- case wasm.OpcodeI32GeU:
- c.emit(
- newOperationGe(signedTypeUint32),
- )
- case wasm.OpcodeI64Eqz:
- c.emit(
- newOperationEqz(unsignedInt64),
- )
- case wasm.OpcodeI64Eq:
- c.emit(
- newOperationEq(unsignedTypeI64),
- )
- case wasm.OpcodeI64Ne:
- c.emit(
- newOperationNe(unsignedTypeI64),
- )
- case wasm.OpcodeI64LtS:
- c.emit(
- newOperationLt(signedTypeInt64),
- )
- case wasm.OpcodeI64LtU:
- c.emit(
- newOperationLt(signedTypeUint64),
- )
- case wasm.OpcodeI64GtS:
- c.emit(
- newOperationGt(signedTypeInt64),
- )
- case wasm.OpcodeI64GtU:
- c.emit(
- newOperationGt(signedTypeUint64),
- )
- case wasm.OpcodeI64LeS:
- c.emit(
- newOperationLe(signedTypeInt64),
- )
- case wasm.OpcodeI64LeU:
- c.emit(
- newOperationLe(signedTypeUint64),
- )
- case wasm.OpcodeI64GeS:
- c.emit(
- newOperationGe(signedTypeInt64),
- )
- case wasm.OpcodeI64GeU:
- c.emit(
- newOperationGe(signedTypeUint64),
- )
- case wasm.OpcodeF32Eq:
- c.emit(
- newOperationEq(unsignedTypeF32),
- )
- case wasm.OpcodeF32Ne:
- c.emit(
- newOperationNe(unsignedTypeF32),
- )
- case wasm.OpcodeF32Lt:
- c.emit(
- newOperationLt(signedTypeFloat32),
- )
- case wasm.OpcodeF32Gt:
- c.emit(
- newOperationGt(signedTypeFloat32),
- )
- case wasm.OpcodeF32Le:
- c.emit(
- newOperationLe(signedTypeFloat32),
- )
- case wasm.OpcodeF32Ge:
- c.emit(
- newOperationGe(signedTypeFloat32),
- )
- case wasm.OpcodeF64Eq:
- c.emit(
- newOperationEq(unsignedTypeF64),
- )
- case wasm.OpcodeF64Ne:
- c.emit(
- newOperationNe(unsignedTypeF64),
- )
- case wasm.OpcodeF64Lt:
- c.emit(
- newOperationLt(signedTypeFloat64),
- )
- case wasm.OpcodeF64Gt:
- c.emit(
- newOperationGt(signedTypeFloat64),
- )
- case wasm.OpcodeF64Le:
- c.emit(
- newOperationLe(signedTypeFloat64),
- )
- case wasm.OpcodeF64Ge:
- c.emit(
- newOperationGe(signedTypeFloat64),
- )
- case wasm.OpcodeI32Clz:
- c.emit(
- newOperationClz(unsignedInt32),
- )
- case wasm.OpcodeI32Ctz:
- c.emit(
- newOperationCtz(unsignedInt32),
- )
- case wasm.OpcodeI32Popcnt:
- c.emit(
- newOperationPopcnt(unsignedInt32),
- )
- case wasm.OpcodeI32Add:
- c.emit(
- newOperationAdd(unsignedTypeI32),
- )
- case wasm.OpcodeI32Sub:
- c.emit(
- newOperationSub(unsignedTypeI32),
- )
- case wasm.OpcodeI32Mul:
- c.emit(
- newOperationMul(unsignedTypeI32),
- )
- case wasm.OpcodeI32DivS:
- c.emit(
- newOperationDiv(signedTypeInt32),
- )
- case wasm.OpcodeI32DivU:
- c.emit(
- newOperationDiv(signedTypeUint32),
- )
- case wasm.OpcodeI32RemS:
- c.emit(
- newOperationRem(signedInt32),
- )
- case wasm.OpcodeI32RemU:
- c.emit(
- newOperationRem(signedUint32),
- )
- case wasm.OpcodeI32And:
- c.emit(
- newOperationAnd(unsignedInt32),
- )
- case wasm.OpcodeI32Or:
- c.emit(
- newOperationOr(unsignedInt32),
- )
- case wasm.OpcodeI32Xor:
- c.emit(
- newOperationXor(unsignedInt64),
- )
- case wasm.OpcodeI32Shl:
- c.emit(
- newOperationShl(unsignedInt32),
- )
- case wasm.OpcodeI32ShrS:
- c.emit(
- newOperationShr(signedInt32),
- )
- case wasm.OpcodeI32ShrU:
- c.emit(
- newOperationShr(signedUint32),
- )
- case wasm.OpcodeI32Rotl:
- c.emit(
- newOperationRotl(unsignedInt32),
- )
- case wasm.OpcodeI32Rotr:
- c.emit(
- newOperationRotr(unsignedInt32),
- )
- case wasm.OpcodeI64Clz:
- c.emit(
- newOperationClz(unsignedInt64),
- )
- case wasm.OpcodeI64Ctz:
- c.emit(
- newOperationCtz(unsignedInt64),
- )
- case wasm.OpcodeI64Popcnt:
- c.emit(
- newOperationPopcnt(unsignedInt64),
- )
- case wasm.OpcodeI64Add:
- c.emit(
- newOperationAdd(unsignedTypeI64),
- )
- case wasm.OpcodeI64Sub:
- c.emit(
- newOperationSub(unsignedTypeI64),
- )
- case wasm.OpcodeI64Mul:
- c.emit(
- newOperationMul(unsignedTypeI64),
- )
- case wasm.OpcodeI64DivS:
- c.emit(
- newOperationDiv(signedTypeInt64),
- )
- case wasm.OpcodeI64DivU:
- c.emit(
- newOperationDiv(signedTypeUint64),
- )
- case wasm.OpcodeI64RemS:
- c.emit(
- newOperationRem(signedInt64),
- )
- case wasm.OpcodeI64RemU:
- c.emit(
- newOperationRem(signedUint64),
- )
- case wasm.OpcodeI64And:
- c.emit(
- newOperationAnd(unsignedInt64),
- )
- case wasm.OpcodeI64Or:
- c.emit(
- newOperationOr(unsignedInt64),
- )
- case wasm.OpcodeI64Xor:
- c.emit(
- newOperationXor(unsignedInt64),
- )
- case wasm.OpcodeI64Shl:
- c.emit(
- newOperationShl(unsignedInt64),
- )
- case wasm.OpcodeI64ShrS:
- c.emit(
- newOperationShr(signedInt64),
- )
- case wasm.OpcodeI64ShrU:
- c.emit(
- newOperationShr(signedUint64),
- )
- case wasm.OpcodeI64Rotl:
- c.emit(
- newOperationRotl(unsignedInt64),
- )
- case wasm.OpcodeI64Rotr:
- c.emit(
- newOperationRotr(unsignedInt64),
- )
- case wasm.OpcodeF32Abs:
- c.emit(
- newOperationAbs(f32),
- )
- case wasm.OpcodeF32Neg:
- c.emit(
- newOperationNeg(f32),
- )
- case wasm.OpcodeF32Ceil:
- c.emit(
- newOperationCeil(f32),
- )
- case wasm.OpcodeF32Floor:
- c.emit(
- newOperationFloor(f32),
- )
- case wasm.OpcodeF32Trunc:
- c.emit(
- newOperationTrunc(f32),
- )
- case wasm.OpcodeF32Nearest:
- c.emit(
- newOperationNearest(f32),
- )
- case wasm.OpcodeF32Sqrt:
- c.emit(
- newOperationSqrt(f32),
- )
- case wasm.OpcodeF32Add:
- c.emit(
- newOperationAdd(unsignedTypeF32),
- )
- case wasm.OpcodeF32Sub:
- c.emit(
- newOperationSub(unsignedTypeF32),
- )
- case wasm.OpcodeF32Mul:
- c.emit(
- newOperationMul(unsignedTypeF32),
- )
- case wasm.OpcodeF32Div:
- c.emit(
- newOperationDiv(signedTypeFloat32),
- )
- case wasm.OpcodeF32Min:
- c.emit(
- newOperationMin(f32),
- )
- case wasm.OpcodeF32Max:
- c.emit(
- newOperationMax(f32),
- )
- case wasm.OpcodeF32Copysign:
- c.emit(
- newOperationCopysign(f32),
- )
- case wasm.OpcodeF64Abs:
- c.emit(
- newOperationAbs(f64),
- )
- case wasm.OpcodeF64Neg:
- c.emit(
- newOperationNeg(f64),
- )
- case wasm.OpcodeF64Ceil:
- c.emit(
- newOperationCeil(f64),
- )
- case wasm.OpcodeF64Floor:
- c.emit(
- newOperationFloor(f64),
- )
- case wasm.OpcodeF64Trunc:
- c.emit(
- newOperationTrunc(f64),
- )
- case wasm.OpcodeF64Nearest:
- c.emit(
- newOperationNearest(f64),
- )
- case wasm.OpcodeF64Sqrt:
- c.emit(
- newOperationSqrt(f64),
- )
- case wasm.OpcodeF64Add:
- c.emit(
- newOperationAdd(unsignedTypeF64),
- )
- case wasm.OpcodeF64Sub:
- c.emit(
- newOperationSub(unsignedTypeF64),
- )
- case wasm.OpcodeF64Mul:
- c.emit(
- newOperationMul(unsignedTypeF64),
- )
- case wasm.OpcodeF64Div:
- c.emit(
- newOperationDiv(signedTypeFloat64),
- )
- case wasm.OpcodeF64Min:
- c.emit(
- newOperationMin(f64),
- )
- case wasm.OpcodeF64Max:
- c.emit(
- newOperationMax(f64),
- )
- case wasm.OpcodeF64Copysign:
- c.emit(
- newOperationCopysign(f64),
- )
- case wasm.OpcodeI32WrapI64:
- c.emit(
- newOperationI32WrapFromI64(),
- )
- case wasm.OpcodeI32TruncF32S:
- c.emit(
- newOperationITruncFromF(f32, signedInt32, false),
- )
- case wasm.OpcodeI32TruncF32U:
- c.emit(
- newOperationITruncFromF(f32, signedUint32, false),
- )
- case wasm.OpcodeI32TruncF64S:
- c.emit(
- newOperationITruncFromF(f64, signedInt32, false),
- )
- case wasm.OpcodeI32TruncF64U:
- c.emit(
- newOperationITruncFromF(f64, signedUint32, false),
- )
- case wasm.OpcodeI64ExtendI32S:
- c.emit(
- newOperationExtend(true),
- )
- case wasm.OpcodeI64ExtendI32U:
- c.emit(
- newOperationExtend(false),
- )
- case wasm.OpcodeI64TruncF32S:
- c.emit(
- newOperationITruncFromF(f32, signedInt64, false),
- )
- case wasm.OpcodeI64TruncF32U:
- c.emit(
- newOperationITruncFromF(f32, signedUint64, false),
- )
- case wasm.OpcodeI64TruncF64S:
- c.emit(
- newOperationITruncFromF(f64, signedInt64, false),
- )
- case wasm.OpcodeI64TruncF64U:
- c.emit(
- newOperationITruncFromF(f64, signedUint64, false),
- )
- case wasm.OpcodeF32ConvertI32S:
- c.emit(
- newOperationFConvertFromI(signedInt32, f32),
- )
- case wasm.OpcodeF32ConvertI32U:
- c.emit(
- newOperationFConvertFromI(signedUint32, f32),
- )
- case wasm.OpcodeF32ConvertI64S:
- c.emit(
- newOperationFConvertFromI(signedInt64, f32),
- )
- case wasm.OpcodeF32ConvertI64U:
- c.emit(
- newOperationFConvertFromI(signedUint64, f32),
- )
- case wasm.OpcodeF32DemoteF64:
- c.emit(
- newOperationF32DemoteFromF64(),
- )
- case wasm.OpcodeF64ConvertI32S:
- c.emit(
- newOperationFConvertFromI(signedInt32, f64),
- )
- case wasm.OpcodeF64ConvertI32U:
- c.emit(
- newOperationFConvertFromI(signedUint32, f64),
- )
- case wasm.OpcodeF64ConvertI64S:
- c.emit(
- newOperationFConvertFromI(signedInt64, f64),
- )
- case wasm.OpcodeF64ConvertI64U:
- c.emit(
- newOperationFConvertFromI(signedUint64, f64),
- )
- case wasm.OpcodeF64PromoteF32:
- c.emit(
- newOperationF64PromoteFromF32(),
- )
- case wasm.OpcodeI32ReinterpretF32:
- c.emit(
- newOperationI32ReinterpretFromF32(),
- )
- case wasm.OpcodeI64ReinterpretF64:
- c.emit(
- newOperationI64ReinterpretFromF64(),
- )
- case wasm.OpcodeF32ReinterpretI32:
- c.emit(
- newOperationF32ReinterpretFromI32(),
- )
- case wasm.OpcodeF64ReinterpretI64:
- c.emit(
- newOperationF64ReinterpretFromI64(),
- )
- case wasm.OpcodeI32Extend8S:
- c.emit(
- newOperationSignExtend32From8(),
- )
- case wasm.OpcodeI32Extend16S:
- c.emit(
- newOperationSignExtend32From16(),
- )
- case wasm.OpcodeI64Extend8S:
- c.emit(
- newOperationSignExtend64From8(),
- )
- case wasm.OpcodeI64Extend16S:
- c.emit(
- newOperationSignExtend64From16(),
- )
- case wasm.OpcodeI64Extend32S:
- c.emit(
- newOperationSignExtend64From32(),
- )
- case wasm.OpcodeRefFunc:
- c.pc++
- index, num, err := leb128.LoadUint32(c.body[c.pc:])
- if err != nil {
- return fmt.Errorf("failed to read function index for ref.func: %v", err)
- }
- c.pc += num - 1
- c.emit(
- newOperationRefFunc(index),
- )
- case wasm.OpcodeRefNull:
- c.pc++ // Skip the type of reftype as every ref value is opaque pointer.
- c.emit(
- newOperationConstI64(0),
- )
- case wasm.OpcodeRefIsNull:
- // Simply compare the opaque pointer (i64) with zero.
- c.emit(
- newOperationEqz(unsignedInt64),
- )
- case wasm.OpcodeTableGet:
- c.pc++
- tableIndex, num, err := leb128.LoadUint32(c.body[c.pc:])
- if err != nil {
- return fmt.Errorf("failed to read function index for table.get: %v", err)
- }
- c.pc += num - 1
- c.emit(
- newOperationTableGet(tableIndex),
- )
- case wasm.OpcodeTableSet:
- c.pc++
- tableIndex, num, err := leb128.LoadUint32(c.body[c.pc:])
- if err != nil {
- return fmt.Errorf("failed to read function index for table.set: %v", err)
- }
- c.pc += num - 1
- c.emit(
- newOperationTableSet(tableIndex),
- )
- case wasm.OpcodeMiscPrefix:
- c.pc++
- // A misc opcode is encoded as an unsigned variable 32-bit integer.
- miscOp, num, err := leb128.LoadUint32(c.body[c.pc:])
- if err != nil {
- return fmt.Errorf("failed to read misc opcode: %v", err)
- }
- c.pc += num - 1
- switch byte(miscOp) {
- case wasm.OpcodeMiscI32TruncSatF32S:
- c.emit(
- newOperationITruncFromF(f32, signedInt32, true),
- )
- case wasm.OpcodeMiscI32TruncSatF32U:
- c.emit(
- newOperationITruncFromF(f32, signedUint32, true),
- )
- case wasm.OpcodeMiscI32TruncSatF64S:
- c.emit(
- newOperationITruncFromF(f64, signedInt32, true),
- )
- case wasm.OpcodeMiscI32TruncSatF64U:
- c.emit(
- newOperationITruncFromF(f64, signedUint32, true),
- )
- case wasm.OpcodeMiscI64TruncSatF32S:
- c.emit(
- newOperationITruncFromF(f32, signedInt64, true),
- )
- case wasm.OpcodeMiscI64TruncSatF32U:
- c.emit(
- newOperationITruncFromF(f32, signedUint64, true),
- )
- case wasm.OpcodeMiscI64TruncSatF64S:
- c.emit(
- newOperationITruncFromF(f64, signedInt64, true),
- )
- case wasm.OpcodeMiscI64TruncSatF64U:
- c.emit(
- newOperationITruncFromF(f64, signedUint64, true),
- )
- case wasm.OpcodeMiscMemoryInit:
- c.result.UsesMemory = true
- dataIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num + 1 // +1 to skip the memory index which is fixed to zero.
- c.emit(
- newOperationMemoryInit(dataIndex),
- )
- case wasm.OpcodeMiscDataDrop:
- dataIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- c.emit(
- newOperationDataDrop(dataIndex),
- )
- case wasm.OpcodeMiscMemoryCopy:
- c.result.UsesMemory = true
- c.pc += 2 // +2 to skip two memory indexes which are fixed to zero.
- c.emit(
- newOperationMemoryCopy(),
- )
- case wasm.OpcodeMiscMemoryFill:
- c.result.UsesMemory = true
- c.pc += 1 // +1 to skip the memory index which is fixed to zero.
- c.emit(
- newOperationMemoryFill(),
- )
- case wasm.OpcodeMiscTableInit:
- elemIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- // Read table index which is fixed to zero currently.
- tableIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- c.emit(
- newOperationTableInit(elemIndex, tableIndex),
- )
- case wasm.OpcodeMiscElemDrop:
- elemIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- c.emit(
- newOperationElemDrop(elemIndex),
- )
- case wasm.OpcodeMiscTableCopy:
- // Read the source table inde.g.
- dst, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- // Read the destination table inde.g.
- src, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- c.emit(
- newOperationTableCopy(src, dst),
- )
- case wasm.OpcodeMiscTableGrow:
- // Read the source table inde.g.
- tableIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- c.emit(
- newOperationTableGrow(tableIndex),
- )
- case wasm.OpcodeMiscTableSize:
- // Read the source table inde.g.
- tableIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- c.emit(
- newOperationTableSize(tableIndex),
- )
- case wasm.OpcodeMiscTableFill:
- // Read the source table index.
- tableIndex, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return fmt.Errorf("reading i32.const value: %v", err)
- }
- c.pc += num
- c.emit(
- newOperationTableFill(tableIndex),
- )
- default:
- return fmt.Errorf("unsupported misc instruction in interpreterir: 0x%x", op)
- }
- case wasm.OpcodeVecPrefix:
- c.pc++
- switch vecOp := c.body[c.pc]; vecOp {
- case wasm.OpcodeVecV128Const:
- c.pc++
- lo := binary.LittleEndian.Uint64(c.body[c.pc : c.pc+8])
- c.pc += 8
- hi := binary.LittleEndian.Uint64(c.body[c.pc : c.pc+8])
- c.emit(
- newOperationV128Const(lo, hi),
- )
- c.pc += 7
- case wasm.OpcodeVecV128Load:
- arg, err := c.readMemoryArg(wasm.OpcodeI32LoadName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType128, arg),
- )
- case wasm.OpcodeVecV128Load8x8s:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load8x8SName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType8x8s, arg),
- )
- case wasm.OpcodeVecV128Load8x8u:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load8x8UName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType8x8u, arg),
- )
- case wasm.OpcodeVecV128Load16x4s:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load16x4SName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType16x4s, arg),
- )
- case wasm.OpcodeVecV128Load16x4u:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load16x4UName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType16x4u, arg),
- )
- case wasm.OpcodeVecV128Load32x2s:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load32x2SName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType32x2s, arg),
- )
- case wasm.OpcodeVecV128Load32x2u:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load32x2UName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType32x2u, arg),
- )
- case wasm.OpcodeVecV128Load8Splat:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load8SplatName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType8Splat, arg),
- )
- case wasm.OpcodeVecV128Load16Splat:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load16SplatName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType16Splat, arg),
- )
- case wasm.OpcodeVecV128Load32Splat:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load32SplatName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType32Splat, arg),
- )
- case wasm.OpcodeVecV128Load64Splat:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load64SplatName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType64Splat, arg),
- )
- case wasm.OpcodeVecV128Load32zero:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load32zeroName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType32zero, arg),
- )
- case wasm.OpcodeVecV128Load64zero:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load64zeroName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Load(v128LoadType64zero, arg),
- )
- case wasm.OpcodeVecV128Load8Lane:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load8LaneName)
- if err != nil {
- return err
- }
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128LoadLane(laneIndex, 8, arg),
- )
- case wasm.OpcodeVecV128Load16Lane:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load16LaneName)
- if err != nil {
- return err
- }
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128LoadLane(laneIndex, 16, arg),
- )
- case wasm.OpcodeVecV128Load32Lane:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load32LaneName)
- if err != nil {
- return err
- }
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128LoadLane(laneIndex, 32, arg),
- )
- case wasm.OpcodeVecV128Load64Lane:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Load64LaneName)
- if err != nil {
- return err
- }
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128LoadLane(laneIndex, 64, arg),
- )
- case wasm.OpcodeVecV128Store:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128StoreName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationV128Store(arg),
- )
- case wasm.OpcodeVecV128Store8Lane:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Store8LaneName)
- if err != nil {
- return err
- }
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128StoreLane(laneIndex, 8, arg),
- )
- case wasm.OpcodeVecV128Store16Lane:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Store16LaneName)
- if err != nil {
- return err
- }
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128StoreLane(laneIndex, 16, arg),
- )
- case wasm.OpcodeVecV128Store32Lane:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Store32LaneName)
- if err != nil {
- return err
- }
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128StoreLane(laneIndex, 32, arg),
- )
- case wasm.OpcodeVecV128Store64Lane:
- arg, err := c.readMemoryArg(wasm.OpcodeVecV128Store64LaneName)
- if err != nil {
- return err
- }
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128StoreLane(laneIndex, 64, arg),
- )
- case wasm.OpcodeVecI8x16ExtractLaneS:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ExtractLane(laneIndex, true, shapeI8x16),
- )
- case wasm.OpcodeVecI8x16ExtractLaneU:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ExtractLane(laneIndex, false, shapeI8x16),
- )
- case wasm.OpcodeVecI16x8ExtractLaneS:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ExtractLane(laneIndex, true, shapeI16x8),
- )
- case wasm.OpcodeVecI16x8ExtractLaneU:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ExtractLane(laneIndex, false, shapeI16x8),
- )
- case wasm.OpcodeVecI32x4ExtractLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ExtractLane(laneIndex, false, shapeI32x4),
- )
- case wasm.OpcodeVecI64x2ExtractLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ExtractLane(laneIndex, false, shapeI64x2),
- )
- case wasm.OpcodeVecF32x4ExtractLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ExtractLane(laneIndex, false, shapeF32x4),
- )
- case wasm.OpcodeVecF64x2ExtractLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ExtractLane(laneIndex, false, shapeF64x2),
- )
- case wasm.OpcodeVecI8x16ReplaceLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ReplaceLane(laneIndex, shapeI8x16),
- )
- case wasm.OpcodeVecI16x8ReplaceLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ReplaceLane(laneIndex, shapeI16x8),
- )
- case wasm.OpcodeVecI32x4ReplaceLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ReplaceLane(laneIndex, shapeI32x4),
- )
- case wasm.OpcodeVecI64x2ReplaceLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ReplaceLane(laneIndex, shapeI64x2),
- )
- case wasm.OpcodeVecF32x4ReplaceLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ReplaceLane(laneIndex, shapeF32x4),
- )
- case wasm.OpcodeVecF64x2ReplaceLane:
- c.pc++
- laneIndex := c.body[c.pc]
- c.emit(
- newOperationV128ReplaceLane(laneIndex, shapeF64x2),
- )
- case wasm.OpcodeVecI8x16Splat:
- c.emit(
- newOperationV128Splat(shapeI8x16),
- )
- case wasm.OpcodeVecI16x8Splat:
- c.emit(
- newOperationV128Splat(shapeI16x8),
- )
- case wasm.OpcodeVecI32x4Splat:
- c.emit(
- newOperationV128Splat(shapeI32x4),
- )
- case wasm.OpcodeVecI64x2Splat:
- c.emit(
- newOperationV128Splat(shapeI64x2),
- )
- case wasm.OpcodeVecF32x4Splat:
- c.emit(
- newOperationV128Splat(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Splat:
- c.emit(
- newOperationV128Splat(shapeF64x2),
- )
- case wasm.OpcodeVecI8x16Swizzle:
- c.emit(
- newOperationV128Swizzle(),
- )
- case wasm.OpcodeVecV128i8x16Shuffle:
- c.pc++
- lanes := make([]uint64, 16)
- for i := uint64(0); i < 16; i++ {
- lanes[i] = uint64(c.body[c.pc+i])
- }
- op := newOperationV128Shuffle(lanes)
- c.emit(op)
- c.pc += 15
- case wasm.OpcodeVecV128AnyTrue:
- c.emit(
- newOperationV128AnyTrue(),
- )
- case wasm.OpcodeVecI8x16AllTrue:
- c.emit(
- newOperationV128AllTrue(shapeI8x16),
- )
- case wasm.OpcodeVecI16x8AllTrue:
- c.emit(
- newOperationV128AllTrue(shapeI16x8),
- )
- case wasm.OpcodeVecI32x4AllTrue:
- c.emit(
- newOperationV128AllTrue(shapeI32x4),
- )
- case wasm.OpcodeVecI64x2AllTrue:
- c.emit(
- newOperationV128AllTrue(shapeI64x2),
- )
- case wasm.OpcodeVecI8x16BitMask:
- c.emit(
- newOperationV128BitMask(shapeI8x16),
- )
- case wasm.OpcodeVecI16x8BitMask:
- c.emit(
- newOperationV128BitMask(shapeI16x8),
- )
- case wasm.OpcodeVecI32x4BitMask:
- c.emit(
- newOperationV128BitMask(shapeI32x4),
- )
- case wasm.OpcodeVecI64x2BitMask:
- c.emit(
- newOperationV128BitMask(shapeI64x2),
- )
- case wasm.OpcodeVecV128And:
- c.emit(
- newOperationV128And(),
- )
- case wasm.OpcodeVecV128Not:
- c.emit(
- newOperationV128Not(),
- )
- case wasm.OpcodeVecV128Or:
- c.emit(
- newOperationV128Or(),
- )
- case wasm.OpcodeVecV128Xor:
- c.emit(
- newOperationV128Xor(),
- )
- case wasm.OpcodeVecV128Bitselect:
- c.emit(
- newOperationV128Bitselect(),
- )
- case wasm.OpcodeVecV128AndNot:
- c.emit(
- newOperationV128AndNot(),
- )
- case wasm.OpcodeVecI8x16Shl:
- c.emit(
- newOperationV128Shl(shapeI8x16),
- )
- case wasm.OpcodeVecI8x16ShrS:
- c.emit(
- newOperationV128Shr(shapeI8x16, true),
- )
- case wasm.OpcodeVecI8x16ShrU:
- c.emit(
- newOperationV128Shr(shapeI8x16, false),
- )
- case wasm.OpcodeVecI16x8Shl:
- c.emit(
- newOperationV128Shl(shapeI16x8),
- )
- case wasm.OpcodeVecI16x8ShrS:
- c.emit(
- newOperationV128Shr(shapeI16x8, true),
- )
- case wasm.OpcodeVecI16x8ShrU:
- c.emit(
- newOperationV128Shr(shapeI16x8, false),
- )
- case wasm.OpcodeVecI32x4Shl:
- c.emit(
- newOperationV128Shl(shapeI32x4),
- )
- case wasm.OpcodeVecI32x4ShrS:
- c.emit(
- newOperationV128Shr(shapeI32x4, true),
- )
- case wasm.OpcodeVecI32x4ShrU:
- c.emit(
- newOperationV128Shr(shapeI32x4, false),
- )
- case wasm.OpcodeVecI64x2Shl:
- c.emit(
- newOperationV128Shl(shapeI64x2),
- )
- case wasm.OpcodeVecI64x2ShrS:
- c.emit(
- newOperationV128Shr(shapeI64x2, true),
- )
- case wasm.OpcodeVecI64x2ShrU:
- c.emit(
- newOperationV128Shr(shapeI64x2, false),
- )
- case wasm.OpcodeVecI8x16Eq:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16Eq),
- )
- case wasm.OpcodeVecI8x16Ne:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16Ne),
- )
- case wasm.OpcodeVecI8x16LtS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16LtS),
- )
- case wasm.OpcodeVecI8x16LtU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16LtU),
- )
- case wasm.OpcodeVecI8x16GtS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16GtS),
- )
- case wasm.OpcodeVecI8x16GtU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16GtU),
- )
- case wasm.OpcodeVecI8x16LeS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16LeS),
- )
- case wasm.OpcodeVecI8x16LeU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16LeU),
- )
- case wasm.OpcodeVecI8x16GeS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16GeS),
- )
- case wasm.OpcodeVecI8x16GeU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI8x16GeU),
- )
- case wasm.OpcodeVecI16x8Eq:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8Eq),
- )
- case wasm.OpcodeVecI16x8Ne:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8Ne),
- )
- case wasm.OpcodeVecI16x8LtS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8LtS),
- )
- case wasm.OpcodeVecI16x8LtU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8LtU),
- )
- case wasm.OpcodeVecI16x8GtS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8GtS),
- )
- case wasm.OpcodeVecI16x8GtU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8GtU),
- )
- case wasm.OpcodeVecI16x8LeS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8LeS),
- )
- case wasm.OpcodeVecI16x8LeU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8LeU),
- )
- case wasm.OpcodeVecI16x8GeS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8GeS),
- )
- case wasm.OpcodeVecI16x8GeU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI16x8GeU),
- )
- case wasm.OpcodeVecI32x4Eq:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4Eq),
- )
- case wasm.OpcodeVecI32x4Ne:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4Ne),
- )
- case wasm.OpcodeVecI32x4LtS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4LtS),
- )
- case wasm.OpcodeVecI32x4LtU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4LtU),
- )
- case wasm.OpcodeVecI32x4GtS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4GtS),
- )
- case wasm.OpcodeVecI32x4GtU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4GtU),
- )
- case wasm.OpcodeVecI32x4LeS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4LeS),
- )
- case wasm.OpcodeVecI32x4LeU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4LeU),
- )
- case wasm.OpcodeVecI32x4GeS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4GeS),
- )
- case wasm.OpcodeVecI32x4GeU:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI32x4GeU),
- )
- case wasm.OpcodeVecI64x2Eq:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI64x2Eq),
- )
- case wasm.OpcodeVecI64x2Ne:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI64x2Ne),
- )
- case wasm.OpcodeVecI64x2LtS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI64x2LtS),
- )
- case wasm.OpcodeVecI64x2GtS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI64x2GtS),
- )
- case wasm.OpcodeVecI64x2LeS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI64x2LeS),
- )
- case wasm.OpcodeVecI64x2GeS:
- c.emit(
- newOperationV128Cmp(v128CmpTypeI64x2GeS),
- )
- case wasm.OpcodeVecF32x4Eq:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF32x4Eq),
- )
- case wasm.OpcodeVecF32x4Ne:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF32x4Ne),
- )
- case wasm.OpcodeVecF32x4Lt:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF32x4Lt),
- )
- case wasm.OpcodeVecF32x4Gt:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF32x4Gt),
- )
- case wasm.OpcodeVecF32x4Le:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF32x4Le),
- )
- case wasm.OpcodeVecF32x4Ge:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF32x4Ge),
- )
- case wasm.OpcodeVecF64x2Eq:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF64x2Eq),
- )
- case wasm.OpcodeVecF64x2Ne:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF64x2Ne),
- )
- case wasm.OpcodeVecF64x2Lt:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF64x2Lt),
- )
- case wasm.OpcodeVecF64x2Gt:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF64x2Gt),
- )
- case wasm.OpcodeVecF64x2Le:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF64x2Le),
- )
- case wasm.OpcodeVecF64x2Ge:
- c.emit(
- newOperationV128Cmp(v128CmpTypeF64x2Ge),
- )
- case wasm.OpcodeVecI8x16Neg:
- c.emit(
- newOperationV128Neg(shapeI8x16),
- )
- case wasm.OpcodeVecI16x8Neg:
- c.emit(
- newOperationV128Neg(shapeI16x8),
- )
- case wasm.OpcodeVecI32x4Neg:
- c.emit(
- newOperationV128Neg(shapeI32x4),
- )
- case wasm.OpcodeVecI64x2Neg:
- c.emit(
- newOperationV128Neg(shapeI64x2),
- )
- case wasm.OpcodeVecF32x4Neg:
- c.emit(
- newOperationV128Neg(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Neg:
- c.emit(
- newOperationV128Neg(shapeF64x2),
- )
- case wasm.OpcodeVecI8x16Add:
- c.emit(
- newOperationV128Add(shapeI8x16),
- )
- case wasm.OpcodeVecI16x8Add:
- c.emit(
- newOperationV128Add(shapeI16x8),
- )
- case wasm.OpcodeVecI32x4Add:
- c.emit(
- newOperationV128Add(shapeI32x4),
- )
- case wasm.OpcodeVecI64x2Add:
- c.emit(
- newOperationV128Add(shapeI64x2),
- )
- case wasm.OpcodeVecF32x4Add:
- c.emit(
- newOperationV128Add(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Add:
- c.emit(
- newOperationV128Add(shapeF64x2),
- )
- case wasm.OpcodeVecI8x16Sub:
- c.emit(
- newOperationV128Sub(shapeI8x16),
- )
- case wasm.OpcodeVecI16x8Sub:
- c.emit(
- newOperationV128Sub(shapeI16x8),
- )
- case wasm.OpcodeVecI32x4Sub:
- c.emit(
- newOperationV128Sub(shapeI32x4),
- )
- case wasm.OpcodeVecI64x2Sub:
- c.emit(
- newOperationV128Sub(shapeI64x2),
- )
- case wasm.OpcodeVecF32x4Sub:
- c.emit(
- newOperationV128Sub(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Sub:
- c.emit(
- newOperationV128Sub(shapeF64x2),
- )
- case wasm.OpcodeVecI8x16AddSatS:
- c.emit(
- newOperationV128AddSat(shapeI8x16, true),
- )
- case wasm.OpcodeVecI8x16AddSatU:
- c.emit(
- newOperationV128AddSat(shapeI8x16, false),
- )
- case wasm.OpcodeVecI16x8AddSatS:
- c.emit(
- newOperationV128AddSat(shapeI16x8, true),
- )
- case wasm.OpcodeVecI16x8AddSatU:
- c.emit(
- newOperationV128AddSat(shapeI16x8, false),
- )
- case wasm.OpcodeVecI8x16SubSatS:
- c.emit(
- newOperationV128SubSat(shapeI8x16, true),
- )
- case wasm.OpcodeVecI8x16SubSatU:
- c.emit(
- newOperationV128SubSat(shapeI8x16, false),
- )
- case wasm.OpcodeVecI16x8SubSatS:
- c.emit(
- newOperationV128SubSat(shapeI16x8, true),
- )
- case wasm.OpcodeVecI16x8SubSatU:
- c.emit(
- newOperationV128SubSat(shapeI16x8, false),
- )
- case wasm.OpcodeVecI16x8Mul:
- c.emit(
- newOperationV128Mul(shapeI16x8),
- )
- case wasm.OpcodeVecI32x4Mul:
- c.emit(
- newOperationV128Mul(shapeI32x4),
- )
- case wasm.OpcodeVecI64x2Mul:
- c.emit(
- newOperationV128Mul(shapeI64x2),
- )
- case wasm.OpcodeVecF32x4Mul:
- c.emit(
- newOperationV128Mul(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Mul:
- c.emit(
- newOperationV128Mul(shapeF64x2),
- )
- case wasm.OpcodeVecF32x4Sqrt:
- c.emit(
- newOperationV128Sqrt(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Sqrt:
- c.emit(
- newOperationV128Sqrt(shapeF64x2),
- )
- case wasm.OpcodeVecF32x4Div:
- c.emit(
- newOperationV128Div(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Div:
- c.emit(
- newOperationV128Div(shapeF64x2),
- )
- case wasm.OpcodeVecI8x16Abs:
- c.emit(
- newOperationV128Abs(shapeI8x16),
- )
- case wasm.OpcodeVecI8x16Popcnt:
- c.emit(
- newOperationV128Popcnt(shapeI8x16),
- )
- case wasm.OpcodeVecI16x8Abs:
- c.emit(
- newOperationV128Abs(shapeI16x8),
- )
- case wasm.OpcodeVecI32x4Abs:
- c.emit(
- newOperationV128Abs(shapeI32x4),
- )
- case wasm.OpcodeVecI64x2Abs:
- c.emit(
- newOperationV128Abs(shapeI64x2),
- )
- case wasm.OpcodeVecF32x4Abs:
- c.emit(
- newOperationV128Abs(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Abs:
- c.emit(
- newOperationV128Abs(shapeF64x2),
- )
- case wasm.OpcodeVecI8x16MinS:
- c.emit(
- newOperationV128Min(shapeI8x16, true),
- )
- case wasm.OpcodeVecI8x16MinU:
- c.emit(
- newOperationV128Min(shapeI8x16, false),
- )
- case wasm.OpcodeVecI8x16MaxS:
- c.emit(
- newOperationV128Max(shapeI8x16, true),
- )
- case wasm.OpcodeVecI8x16MaxU:
- c.emit(
- newOperationV128Max(shapeI8x16, false),
- )
- case wasm.OpcodeVecI8x16AvgrU:
- c.emit(
- newOperationV128AvgrU(shapeI8x16),
- )
- case wasm.OpcodeVecI16x8MinS:
- c.emit(
- newOperationV128Min(shapeI16x8, true),
- )
- case wasm.OpcodeVecI16x8MinU:
- c.emit(
- newOperationV128Min(shapeI16x8, false),
- )
- case wasm.OpcodeVecI16x8MaxS:
- c.emit(
- newOperationV128Max(shapeI16x8, true),
- )
- case wasm.OpcodeVecI16x8MaxU:
- c.emit(
- newOperationV128Max(shapeI16x8, false),
- )
- case wasm.OpcodeVecI16x8AvgrU:
- c.emit(
- newOperationV128AvgrU(shapeI16x8),
- )
- case wasm.OpcodeVecI32x4MinS:
- c.emit(
- newOperationV128Min(shapeI32x4, true),
- )
- case wasm.OpcodeVecI32x4MinU:
- c.emit(
- newOperationV128Min(shapeI32x4, false),
- )
- case wasm.OpcodeVecI32x4MaxS:
- c.emit(
- newOperationV128Max(shapeI32x4, true),
- )
- case wasm.OpcodeVecI32x4MaxU:
- c.emit(
- newOperationV128Max(shapeI32x4, false),
- )
- case wasm.OpcodeVecF32x4Min:
- c.emit(
- newOperationV128Min(shapeF32x4, false),
- )
- case wasm.OpcodeVecF32x4Max:
- c.emit(
- newOperationV128Max(shapeF32x4, false),
- )
- case wasm.OpcodeVecF64x2Min:
- c.emit(
- newOperationV128Min(shapeF64x2, false),
- )
- case wasm.OpcodeVecF64x2Max:
- c.emit(
- newOperationV128Max(shapeF64x2, false),
- )
- case wasm.OpcodeVecF32x4Pmin:
- c.emit(
- newOperationV128Pmin(shapeF32x4),
- )
- case wasm.OpcodeVecF32x4Pmax:
- c.emit(
- newOperationV128Pmax(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Pmin:
- c.emit(
- newOperationV128Pmin(shapeF64x2),
- )
- case wasm.OpcodeVecF64x2Pmax:
- c.emit(
- newOperationV128Pmax(shapeF64x2),
- )
- case wasm.OpcodeVecF32x4Ceil:
- c.emit(
- newOperationV128Ceil(shapeF32x4),
- )
- case wasm.OpcodeVecF32x4Floor:
- c.emit(
- newOperationV128Floor(shapeF32x4),
- )
- case wasm.OpcodeVecF32x4Trunc:
- c.emit(
- newOperationV128Trunc(shapeF32x4),
- )
- case wasm.OpcodeVecF32x4Nearest:
- c.emit(
- newOperationV128Nearest(shapeF32x4),
- )
- case wasm.OpcodeVecF64x2Ceil:
- c.emit(
- newOperationV128Ceil(shapeF64x2),
- )
- case wasm.OpcodeVecF64x2Floor:
- c.emit(
- newOperationV128Floor(shapeF64x2),
- )
- case wasm.OpcodeVecF64x2Trunc:
- c.emit(
- newOperationV128Trunc(shapeF64x2),
- )
- case wasm.OpcodeVecF64x2Nearest:
- c.emit(
- newOperationV128Nearest(shapeF64x2),
- )
- case wasm.OpcodeVecI16x8ExtendLowI8x16S:
- c.emit(
- newOperationV128Extend(shapeI8x16, true, true),
- )
- case wasm.OpcodeVecI16x8ExtendHighI8x16S:
- c.emit(
- newOperationV128Extend(shapeI8x16, true, false),
- )
- case wasm.OpcodeVecI16x8ExtendLowI8x16U:
- c.emit(
- newOperationV128Extend(shapeI8x16, false, true),
- )
- case wasm.OpcodeVecI16x8ExtendHighI8x16U:
- c.emit(
- newOperationV128Extend(shapeI8x16, false, false),
- )
- case wasm.OpcodeVecI32x4ExtendLowI16x8S:
- c.emit(
- newOperationV128Extend(shapeI16x8, true, true),
- )
- case wasm.OpcodeVecI32x4ExtendHighI16x8S:
- c.emit(
- newOperationV128Extend(shapeI16x8, true, false),
- )
- case wasm.OpcodeVecI32x4ExtendLowI16x8U:
- c.emit(
- newOperationV128Extend(shapeI16x8, false, true),
- )
- case wasm.OpcodeVecI32x4ExtendHighI16x8U:
- c.emit(
- newOperationV128Extend(shapeI16x8, false, false),
- )
- case wasm.OpcodeVecI64x2ExtendLowI32x4S:
- c.emit(
- newOperationV128Extend(shapeI32x4, true, true),
- )
- case wasm.OpcodeVecI64x2ExtendHighI32x4S:
- c.emit(
- newOperationV128Extend(shapeI32x4, true, false),
- )
- case wasm.OpcodeVecI64x2ExtendLowI32x4U:
- c.emit(
- newOperationV128Extend(shapeI32x4, false, true),
- )
- case wasm.OpcodeVecI64x2ExtendHighI32x4U:
- c.emit(
- newOperationV128Extend(shapeI32x4, false, false),
- )
- case wasm.OpcodeVecI16x8Q15mulrSatS:
- c.emit(
- newOperationV128Q15mulrSatS(),
- )
- case wasm.OpcodeVecI16x8ExtMulLowI8x16S:
- c.emit(
- newOperationV128ExtMul(shapeI8x16, true, true),
- )
- case wasm.OpcodeVecI16x8ExtMulHighI8x16S:
- c.emit(
- newOperationV128ExtMul(shapeI8x16, true, false),
- )
- case wasm.OpcodeVecI16x8ExtMulLowI8x16U:
- c.emit(
- newOperationV128ExtMul(shapeI8x16, false, true),
- )
- case wasm.OpcodeVecI16x8ExtMulHighI8x16U:
- c.emit(
- newOperationV128ExtMul(shapeI8x16, false, false),
- )
- case wasm.OpcodeVecI32x4ExtMulLowI16x8S:
- c.emit(
- newOperationV128ExtMul(shapeI16x8, true, true),
- )
- case wasm.OpcodeVecI32x4ExtMulHighI16x8S:
- c.emit(
- newOperationV128ExtMul(shapeI16x8, true, false),
- )
- case wasm.OpcodeVecI32x4ExtMulLowI16x8U:
- c.emit(
- newOperationV128ExtMul(shapeI16x8, false, true),
- )
- case wasm.OpcodeVecI32x4ExtMulHighI16x8U:
- c.emit(
- newOperationV128ExtMul(shapeI16x8, false, false),
- )
- case wasm.OpcodeVecI64x2ExtMulLowI32x4S:
- c.emit(
- newOperationV128ExtMul(shapeI32x4, true, true),
- )
- case wasm.OpcodeVecI64x2ExtMulHighI32x4S:
- c.emit(
- newOperationV128ExtMul(shapeI32x4, true, false),
- )
- case wasm.OpcodeVecI64x2ExtMulLowI32x4U:
- c.emit(
- newOperationV128ExtMul(shapeI32x4, false, true),
- )
- case wasm.OpcodeVecI64x2ExtMulHighI32x4U:
- c.emit(
- newOperationV128ExtMul(shapeI32x4, false, false),
- )
- case wasm.OpcodeVecI16x8ExtaddPairwiseI8x16S:
- c.emit(
- newOperationV128ExtAddPairwise(shapeI8x16, true),
- )
- case wasm.OpcodeVecI16x8ExtaddPairwiseI8x16U:
- c.emit(
- newOperationV128ExtAddPairwise(shapeI8x16, false),
- )
- case wasm.OpcodeVecI32x4ExtaddPairwiseI16x8S:
- c.emit(
- newOperationV128ExtAddPairwise(shapeI16x8, true),
- )
- case wasm.OpcodeVecI32x4ExtaddPairwiseI16x8U:
- c.emit(
- newOperationV128ExtAddPairwise(shapeI16x8, false),
- )
- case wasm.OpcodeVecF64x2PromoteLowF32x4Zero:
- c.emit(
- newOperationV128FloatPromote(),
- )
- case wasm.OpcodeVecF32x4DemoteF64x2Zero:
- c.emit(
- newOperationV128FloatDemote(),
- )
- case wasm.OpcodeVecF32x4ConvertI32x4S:
- c.emit(
- newOperationV128FConvertFromI(shapeF32x4, true),
- )
- case wasm.OpcodeVecF32x4ConvertI32x4U:
- c.emit(
- newOperationV128FConvertFromI(shapeF32x4, false),
- )
- case wasm.OpcodeVecF64x2ConvertLowI32x4S:
- c.emit(
- newOperationV128FConvertFromI(shapeF64x2, true),
- )
- case wasm.OpcodeVecF64x2ConvertLowI32x4U:
- c.emit(
- newOperationV128FConvertFromI(shapeF64x2, false),
- )
- case wasm.OpcodeVecI32x4DotI16x8S:
- c.emit(
- newOperationV128Dot(),
- )
- case wasm.OpcodeVecI8x16NarrowI16x8S:
- c.emit(
- newOperationV128Narrow(shapeI16x8, true),
- )
- case wasm.OpcodeVecI8x16NarrowI16x8U:
- c.emit(
- newOperationV128Narrow(shapeI16x8, false),
- )
- case wasm.OpcodeVecI16x8NarrowI32x4S:
- c.emit(
- newOperationV128Narrow(shapeI32x4, true),
- )
- case wasm.OpcodeVecI16x8NarrowI32x4U:
- c.emit(
- newOperationV128Narrow(shapeI32x4, false),
- )
- case wasm.OpcodeVecI32x4TruncSatF32x4S:
- c.emit(
- newOperationV128ITruncSatFromF(shapeF32x4, true),
- )
- case wasm.OpcodeVecI32x4TruncSatF32x4U:
- c.emit(
- newOperationV128ITruncSatFromF(shapeF32x4, false),
- )
- case wasm.OpcodeVecI32x4TruncSatF64x2SZero:
- c.emit(
- newOperationV128ITruncSatFromF(shapeF64x2, true),
- )
- case wasm.OpcodeVecI32x4TruncSatF64x2UZero:
- c.emit(
- newOperationV128ITruncSatFromF(shapeF64x2, false),
- )
- default:
- return fmt.Errorf("unsupported vector instruction in interpreterir: %s", wasm.VectorInstructionName(vecOp))
- }
- case wasm.OpcodeAtomicPrefix:
- c.pc++
- atomicOp := c.body[c.pc]
- switch atomicOp {
- case wasm.OpcodeAtomicMemoryWait32:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicMemoryWait32Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicMemoryWait(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicMemoryWait64:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicMemoryWait64Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicMemoryWait(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicMemoryNotify:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicMemoryNotifyName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicMemoryNotify(imm),
- )
- case wasm.OpcodeAtomicFence:
- // Skip immediate value
- c.pc++
- _ = c.body[c.pc]
- c.emit(
- newOperationAtomicFence(),
- )
- case wasm.OpcodeAtomicI32Load:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32LoadName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicLoad(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI64Load:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64LoadName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicLoad(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicI32Load8U:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Load8UName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicLoad8(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI32Load16U:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Load16UName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicLoad16(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI64Load8U:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Load8UName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicLoad8(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicI64Load16U:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Load16UName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicLoad16(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicI64Load32U:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Load32UName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicLoad(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI32Store:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32StoreName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicStore(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI32Store8:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Store8Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicStore8(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI32Store16:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Store16Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicStore16(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI64Store:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64StoreName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicStore(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicI64Store8:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Store8Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicStore8(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicI64Store16:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Store16Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicStore16(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicI64Store32:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Store32Name)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicStore(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI32RmwAdd:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32RmwAddName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpAdd),
- )
- case wasm.OpcodeAtomicI64RmwAdd:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64RmwAddName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI64, imm, atomicArithmeticOpAdd),
- )
- case wasm.OpcodeAtomicI32Rmw8AddU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw8AddUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI32, imm, atomicArithmeticOpAdd),
- )
- case wasm.OpcodeAtomicI64Rmw8AddU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw8AddUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI64, imm, atomicArithmeticOpAdd),
- )
- case wasm.OpcodeAtomicI32Rmw16AddU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw16AddUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI32, imm, atomicArithmeticOpAdd),
- )
- case wasm.OpcodeAtomicI64Rmw16AddU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw16AddUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI64, imm, atomicArithmeticOpAdd),
- )
- case wasm.OpcodeAtomicI64Rmw32AddU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw32AddUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpAdd),
- )
- case wasm.OpcodeAtomicI32RmwSub:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32RmwSubName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpSub),
- )
- case wasm.OpcodeAtomicI64RmwSub:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64RmwSubName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI64, imm, atomicArithmeticOpSub),
- )
- case wasm.OpcodeAtomicI32Rmw8SubU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw8SubUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI32, imm, atomicArithmeticOpSub),
- )
- case wasm.OpcodeAtomicI64Rmw8SubU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw8SubUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI64, imm, atomicArithmeticOpSub),
- )
- case wasm.OpcodeAtomicI32Rmw16SubU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw16SubUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI32, imm, atomicArithmeticOpSub),
- )
- case wasm.OpcodeAtomicI64Rmw16SubU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw16SubUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI64, imm, atomicArithmeticOpSub),
- )
- case wasm.OpcodeAtomicI64Rmw32SubU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw32SubUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpSub),
- )
- case wasm.OpcodeAtomicI32RmwAnd:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32RmwAndName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpAnd),
- )
- case wasm.OpcodeAtomicI64RmwAnd:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64RmwAndName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI64, imm, atomicArithmeticOpAnd),
- )
- case wasm.OpcodeAtomicI32Rmw8AndU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw8AndUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI32, imm, atomicArithmeticOpAnd),
- )
- case wasm.OpcodeAtomicI64Rmw8AndU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw8AndUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI64, imm, atomicArithmeticOpAnd),
- )
- case wasm.OpcodeAtomicI32Rmw16AndU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw16AndUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI32, imm, atomicArithmeticOpAnd),
- )
- case wasm.OpcodeAtomicI64Rmw16AndU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw16AndUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI64, imm, atomicArithmeticOpAnd),
- )
- case wasm.OpcodeAtomicI64Rmw32AndU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw32AndUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpAnd),
- )
- case wasm.OpcodeAtomicI32RmwOr:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32RmwOrName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpOr),
- )
- case wasm.OpcodeAtomicI64RmwOr:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64RmwOrName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI64, imm, atomicArithmeticOpOr),
- )
- case wasm.OpcodeAtomicI32Rmw8OrU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw8OrUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI32, imm, atomicArithmeticOpOr),
- )
- case wasm.OpcodeAtomicI64Rmw8OrU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw8OrUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI64, imm, atomicArithmeticOpOr),
- )
- case wasm.OpcodeAtomicI32Rmw16OrU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw16OrUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI32, imm, atomicArithmeticOpOr),
- )
- case wasm.OpcodeAtomicI64Rmw16OrU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw16OrUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI64, imm, atomicArithmeticOpOr),
- )
- case wasm.OpcodeAtomicI64Rmw32OrU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw32OrUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpOr),
- )
- case wasm.OpcodeAtomicI32RmwXor:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32RmwXorName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpXor),
- )
- case wasm.OpcodeAtomicI64RmwXor:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64RmwXorName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI64, imm, atomicArithmeticOpXor),
- )
- case wasm.OpcodeAtomicI32Rmw8XorU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw8XorUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI32, imm, atomicArithmeticOpXor),
- )
- case wasm.OpcodeAtomicI64Rmw8XorU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw8XorUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI64, imm, atomicArithmeticOpXor),
- )
- case wasm.OpcodeAtomicI32Rmw16XorU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw16XorUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI32, imm, atomicArithmeticOpXor),
- )
- case wasm.OpcodeAtomicI64Rmw16XorU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw16XorUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI64, imm, atomicArithmeticOpXor),
- )
- case wasm.OpcodeAtomicI64Rmw32XorU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw32XorUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpXor),
- )
- case wasm.OpcodeAtomicI32RmwXchg:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32RmwXchgName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpNop),
- )
- case wasm.OpcodeAtomicI64RmwXchg:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64RmwXchgName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI64, imm, atomicArithmeticOpNop),
- )
- case wasm.OpcodeAtomicI32Rmw8XchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw8XchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI32, imm, atomicArithmeticOpNop),
- )
- case wasm.OpcodeAtomicI64Rmw8XchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw8XchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8(unsignedTypeI64, imm, atomicArithmeticOpNop),
- )
- case wasm.OpcodeAtomicI32Rmw16XchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw16XchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI32, imm, atomicArithmeticOpNop),
- )
- case wasm.OpcodeAtomicI64Rmw16XchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw16XchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16(unsignedTypeI64, imm, atomicArithmeticOpNop),
- )
- case wasm.OpcodeAtomicI64Rmw32XchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw32XchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW(unsignedTypeI32, imm, atomicArithmeticOpNop),
- )
- case wasm.OpcodeAtomicI32RmwCmpxchg:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32RmwCmpxchgName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMWCmpxchg(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI64RmwCmpxchg:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64RmwCmpxchgName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMWCmpxchg(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicI32Rmw8CmpxchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw8CmpxchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8Cmpxchg(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI64Rmw8CmpxchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw8CmpxchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW8Cmpxchg(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicI32Rmw16CmpxchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI32Rmw16CmpxchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16Cmpxchg(unsignedTypeI32, imm),
- )
- case wasm.OpcodeAtomicI64Rmw16CmpxchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw16CmpxchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMW16Cmpxchg(unsignedTypeI64, imm),
- )
- case wasm.OpcodeAtomicI64Rmw32CmpxchgU:
- imm, err := c.readMemoryArg(wasm.OpcodeAtomicI64Rmw32CmpxchgUName)
- if err != nil {
- return err
- }
- c.emit(
- newOperationAtomicRMWCmpxchg(unsignedTypeI32, imm),
- )
- default:
- return fmt.Errorf("unsupported atomic instruction in interpreterir: %s", wasm.AtomicInstructionName(atomicOp))
- }
- default:
- return fmt.Errorf("unsupported instruction in interpreterir: 0x%x", op)
- }
-
- // Move the program counter to point to the next instruction.
- c.pc++
- return nil
-}
-
-func (c *compiler) nextFrameID() (id uint32) {
- id = c.currentFrameID + 1
- c.currentFrameID++
- return
-}
-
-func (c *compiler) applyToStack(opcode wasm.Opcode) (index uint32, err error) {
- switch opcode {
- case
- // These are the opcodes that is coupled with "index" immediate
- // and it DOES affect the signature of opcode.
- wasm.OpcodeCall,
- wasm.OpcodeCallIndirect,
- wasm.OpcodeLocalGet,
- wasm.OpcodeLocalSet,
- wasm.OpcodeLocalTee,
- wasm.OpcodeGlobalGet,
- wasm.OpcodeGlobalSet:
- // Assumes that we are at the opcode now so skip it before read immediates.
- v, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return 0, fmt.Errorf("reading immediates: %w", err)
- }
- c.pc += num
- index = v
- default:
- // Note that other opcodes are free of index
- // as it doesn't affect the signature of opt code.
- // In other words, the "index" argument of wasmOpcodeSignature
- // is ignored there.
- }
-
- if c.unreachableState.on {
- return 0, nil
- }
-
- // Retrieve the signature of the opcode.
- s, err := c.wasmOpcodeSignature(opcode, index)
- if err != nil {
- return 0, err
- }
-
- // Manipulate the stack according to the signature.
- // Note that the following algorithm assumes that
- // the unknown type is unique in the signature,
- // and is determined by the actual type on the stack.
- // The determined type is stored in this typeParam.
- var typeParam unsignedType
- var typeParamFound bool
- for i := range s.in {
- want := s.in[len(s.in)-1-i]
- actual := c.stackPop()
- if want == unsignedTypeUnknown && typeParamFound {
- want = typeParam
- } else if want == unsignedTypeUnknown {
- want = actual
- typeParam = want
- typeParamFound = true
- }
- if want != actual {
- return 0, fmt.Errorf("input signature mismatch: want %s but have %s", want, actual)
- }
- }
-
- for _, target := range s.out {
- if target == unsignedTypeUnknown && !typeParamFound {
- return 0, fmt.Errorf("cannot determine type of unknown result")
- } else if target == unsignedTypeUnknown {
- c.stackPush(typeParam)
- } else {
- c.stackPush(target)
- }
- }
-
- return index, nil
-}
-
-func (c *compiler) stackPeek() (ret unsignedType) {
- ret = c.stack[len(c.stack)-1]
- return
-}
-
-func (c *compiler) stackSwitchAt(frame *controlFrame) {
- c.stack = c.stack[:frame.originalStackLenWithoutParam]
- c.stackLenInUint64 = frame.originalStackLenWithoutParamUint64
-}
-
-func (c *compiler) stackPop() (ret unsignedType) {
- // No need to check stack bound
- // as we can assume that all the operations
- // are valid thanks to validateFunction
- // at module validation phase.
- ret = c.stack[len(c.stack)-1]
- c.stack = c.stack[:len(c.stack)-1]
- c.stackLenInUint64 -= 1 + int(unsignedTypeV128&ret>>2)
- return
-}
-
-func (c *compiler) stackPush(ts unsignedType) {
- c.stack = append(c.stack, ts)
- c.stackLenInUint64 += 1 + int(unsignedTypeV128&ts>>2)
-}
-
-// emit adds the operations into the result.
-func (c *compiler) emit(op unionOperation) {
- if !c.unreachableState.on {
- switch op.Kind {
- case operationKindDrop:
- // If the drop range is nil,
- // we could remove such operations.
- // That happens when drop operation is unnecessary.
- // i.e. when there's no need to adjust stack before jmp.
- if int64(op.U1) == -1 {
- return
- }
- }
- c.result.Operations = append(c.result.Operations, op)
- if c.needSourceOffset {
- c.result.IROperationSourceOffsetsInWasmBinary = append(c.result.IROperationSourceOffsetsInWasmBinary,
- c.currentOpPC+c.bodyOffsetInCodeSection)
- }
- }
-}
-
-// Emit const expression with default values of the given type.
-func (c *compiler) emitDefaultValue(t wasm.ValueType) {
- switch t {
- case wasm.ValueTypeI32:
- c.stackPush(unsignedTypeI32)
- c.emit(newOperationConstI32(0))
- case wasm.ValueTypeI64, wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
- c.stackPush(unsignedTypeI64)
- c.emit(newOperationConstI64(0))
- case wasm.ValueTypeF32:
- c.stackPush(unsignedTypeF32)
- c.emit(newOperationConstF32(0))
- case wasm.ValueTypeF64:
- c.stackPush(unsignedTypeF64)
- c.emit(newOperationConstF64(0))
- case wasm.ValueTypeV128:
- c.stackPush(unsignedTypeV128)
- c.emit(newOperationV128Const(0, 0))
- }
-}
-
-// Returns the "depth" (starting from top of the stack)
-// of the n-th local.
-func (c *compiler) localDepth(index wasm.Index) int {
- height := c.localIndexToStackHeightInUint64[index]
- return c.stackLenInUint64 - 1 - height
-}
-
-func (c *compiler) localType(index wasm.Index) (t wasm.ValueType) {
- if params := uint32(len(c.sig.Params)); index < params {
- t = c.sig.Params[index]
- } else {
- t = c.localTypes[index-params]
- }
- return
-}
-
-// getFrameDropRange returns the range (starting from top of the stack) that spans across the (uint64) stack. The range is
-// supposed to be dropped from the stack when the given frame exists or branch into it.
-//
-// * frame is the control frame which the call-site is trying to branch into or exit.
-// * isEnd true if the call-site is handling wasm.OpcodeEnd.
-func (c *compiler) getFrameDropRange(frame *controlFrame, isEnd bool) inclusiveRange {
- var start int
- if !isEnd && frame.kind == controlFrameKindLoop {
- // If this is not End and the call-site is trying to branch into the Loop control frame,
- // we have to Start executing from the beginning of the loop block.
- // Therefore, we have to pass the inputs to the frame.
- start = frame.blockType.ParamNumInUint64
- } else {
- start = frame.blockType.ResultNumInUint64
- }
- end := c.stackLenInUint64 - 1 - frame.originalStackLenWithoutParamUint64
- if start <= end {
- return inclusiveRange{Start: int32(start), End: int32(end)}
- } else {
- return nopinclusiveRange
- }
-}
-
-func (c *compiler) readMemoryArg(tag string) (memoryArg, error) {
- c.result.UsesMemory = true
- alignment, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return memoryArg{}, fmt.Errorf("reading alignment for %s: %w", tag, err)
- }
- c.pc += num
- offset, num, err := leb128.LoadUint32(c.body[c.pc+1:])
- if err != nil {
- return memoryArg{}, fmt.Errorf("reading offset for %s: %w", tag, err)
- }
- c.pc += num
- return memoryArg{Offset: offset, Alignment: alignment}, nil
-}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/format.go b/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/format.go
deleted file mode 100644
index 8af1d94b0..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/format.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package interpreter
-
-import (
- "bytes"
-)
-
-func format(ops []unionOperation) string {
- buf := bytes.NewBuffer(nil)
-
- _, _ = buf.WriteString(".entrypoint\n")
- for i := range ops {
- op := &ops[i]
- str := op.String()
- isLabel := op.Kind == operationKindLabel
- if !isLabel {
- const indent = "\t"
- str = indent + str
- }
- _, _ = buf.WriteString(str + "\n")
- }
- return buf.String()
-}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/interpreter.go b/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/interpreter.go
deleted file mode 100644
index 5b5e6e9d0..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/interpreter.go
+++ /dev/null
@@ -1,4596 +0,0 @@
-package interpreter
-
-import (
- "context"
- "encoding/binary"
- "errors"
- "fmt"
- "math"
- "math/bits"
- "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"
-)
-
-// callStackCeiling is the maximum WebAssembly call frame stack height. This allows wazero to raise
-// wasm.ErrCallStackOverflow instead of overflowing the Go runtime.
-//
-// The default value should suffice for most use cases. Those wishing to change this can via `go build -ldflags`.
-var callStackCeiling = 2000
-
-// engine is an interpreter implementation of wasm.Engine
-type engine struct {
- enabledFeatures api.CoreFeatures
- compiledFunctions map[wasm.ModuleID][]compiledFunction // guarded by mutex.
- mux sync.RWMutex
-}
-
-func NewEngine(_ context.Context, enabledFeatures api.CoreFeatures, _ filecache.Cache) wasm.Engine {
- return &engine{
- enabledFeatures: enabledFeatures,
- compiledFunctions: map[wasm.ModuleID][]compiledFunction{},
- }
-}
-
-// Close implements the same method as documented on wasm.Engine.
-func (e *engine) Close() (err error) {
- return
-}
-
-// CompiledModuleCount implements the same method as documented on wasm.Engine.
-func (e *engine) CompiledModuleCount() uint32 {
- return uint32(len(e.compiledFunctions))
-}
-
-// DeleteCompiledModule implements the same method as documented on wasm.Engine.
-func (e *engine) DeleteCompiledModule(m *wasm.Module) {
- e.deleteCompiledFunctions(m)
-}
-
-func (e *engine) deleteCompiledFunctions(module *wasm.Module) {
- e.mux.Lock()
- defer e.mux.Unlock()
- delete(e.compiledFunctions, module.ID)
-}
-
-func (e *engine) addCompiledFunctions(module *wasm.Module, fs []compiledFunction) {
- e.mux.Lock()
- defer e.mux.Unlock()
- e.compiledFunctions[module.ID] = fs
-}
-
-func (e *engine) getCompiledFunctions(module *wasm.Module) (fs []compiledFunction, ok bool) {
- e.mux.RLock()
- defer e.mux.RUnlock()
- fs, ok = e.compiledFunctions[module.ID]
- return
-}
-
-// moduleEngine implements wasm.ModuleEngine
-type moduleEngine struct {
- // codes are the compiled functions in a module instances.
- // The index is module instance-scoped.
- functions []function
-
- // parentEngine holds *engine from which this module engine is created from.
- parentEngine *engine
-}
-
-// GetGlobalValue implements the same method as documented on wasm.ModuleEngine.
-func (e *moduleEngine) GetGlobalValue(wasm.Index) (lo, hi uint64) {
- panic("BUG: GetGlobalValue should never be called on interpreter mode")
-}
-
-// SetGlobalValue implements the same method as documented on wasm.ModuleEngine.
-func (e *moduleEngine) SetGlobalValue(idx wasm.Index, lo, hi uint64) {
- panic("BUG: SetGlobalValue should never be called on interpreter mode")
-}
-
-// OwnsGlobals implements the same method as documented on wasm.ModuleEngine.
-func (e *moduleEngine) OwnsGlobals() bool { return false }
-
-// MemoryGrown implements wasm.ModuleEngine.
-func (e *moduleEngine) MemoryGrown() {}
-
-// callEngine holds context per moduleEngine.Call, and shared across all the
-// function calls originating from the same moduleEngine.Call execution.
-//
-// This implements api.Function.
-type callEngine struct {
- internalapi.WazeroOnlyType
-
- // stack contains the operands.
- // Note that all the values are represented as uint64.
- stack []uint64
-
- // frames are the function call stack.
- frames []*callFrame
-
- // f is the initial function for this call engine.
- f *function
-
- // stackiterator for Listeners to walk frames and stack.
- 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) {
- // No need to check stack bound
- // as we can assume that all the operations
- // are valid thanks to validateFunction
- // at module validation phase
- // and interpreterir translation
- // before compilation.
- 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]
-}
-
-// peekValues peeks api.ValueType values from the stack and returns them.
-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) {
- // No need to check stack bound as we can assume that all the operations are valid thanks to validateFunction at
- // module validation phase and interpreterir translation before compilation.
- oneLess := len(ce.frames) - 1
- frame = ce.frames[oneLess]
- ce.frames = ce.frames[:oneLess]
- return
-}
-
-type callFrame struct {
- // pc is the program counter representing the current position in code.body.
- pc uint64
- // f is the compiled function used in this function frame.
- f *function
- // base index in the frame of this function, used to detect the count of
- // values on the stack.
- 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
-}
-
-// functionFromUintptr resurrects the original *function from the given uintptr
-// which comes from either funcref table or OpcodeRefFunc instruction.
-func functionFromUintptr(ptr uintptr) *function {
- // Wraps ptrs as the double pointer in order to avoid the unsafe access as detected by race detector.
- //
- // For example, if we have (*function)(unsafe.Pointer(ptr)) instead, then the race detector's "checkptr"
- // subroutine wanrs as "checkptr: pointer arithmetic result points to invalid allocation"
- // https://github.com/golang/go/blob/1ce7fcf139417d618c2730010ede2afb41664211/src/runtime/checkptr.go#L69
- var wrapped *uintptr = &ptr
- return *(**function)(unsafe.Pointer(wrapped))
-}
-
-type snapshot struct {
- stack []uint64
- frames []*callFrame
- pc uint64
-
- ret []uint64
-
- ce *callEngine
-}
-
-// Snapshot implements the same method as documented on experimental.Snapshotter.
-func (ce *callEngine) Snapshot() experimental.Snapshot {
- stack := make([]uint64, len(ce.stack))
- copy(stack, ce.stack)
-
- frames := make([]*callFrame, len(ce.frames))
- copy(frames, ce.frames)
-
- return &snapshot{
- stack: stack,
- frames: frames,
- ce: ce,
- }
-}
-
-// Restore implements the same method as documented on experimental.Snapshot.
-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)
-}
-
-// Error implements the same method on error.
-func (s *snapshot) Error() string {
- return "unhandled snapshot restore, this generally indicates restore was called from a different " +
- "exported function invocation than snapshot"
-}
-
-// stackIterator implements experimental.StackIterator.
-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
-}
-
-// Next implements the same method as documented on experimental.StackIterator.
-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
-}
-
-// Function implements the same method as documented on
-// experimental.StackIterator.
-func (si *stackIterator) Function() experimental.InternalFunction {
- return internalFunction{si.fn}
-}
-
-// ProgramCounter implements the same method as documented on
-// experimental.StackIterator.
-func (si *stackIterator) ProgramCounter() experimental.ProgramCounter {
- return experimental.ProgramCounter(si.pc)
-}
-
-// internalFunction implements experimental.InternalFunction.
-type internalFunction struct{ *function }
-
-// Definition implements the same method as documented on
-// experimental.InternalFunction.
-func (f internalFunction) Definition() api.FunctionDefinition {
- return f.definition()
-}
-
-// SourceOffsetForPC implements the same method as documented on
-// experimental.InternalFunction.
-func (f internalFunction) SourceOffsetForPC(pc experimental.ProgramCounter) uint64 {
- offsetsMap := f.parent.offsetsInWasmBinary
- if uint64(pc) < uint64(len(offsetsMap)) {
- return offsetsMap[pc]
- }
- return 0
-}
-
-// interpreter mode doesn't maintain call frames in the stack, so pass the zero size to the IR.
-const callFrameStackSize = 0
-
-// CompileModule implements the same method as documented on wasm.Engine.
-func (e *engine) CompileModule(_ context.Context, module *wasm.Module, listeners []experimental.FunctionListener, ensureTermination bool) error {
- if _, ok := e.getCompiledFunctions(module); ok { // cache hit!
- 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 this is the host function, there's nothing to do as the runtime representation of
- // host function in interpreter is its Go function itself as opposed to Wasm functions,
- // which need to be compiled down to
- 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
-}
-
-// NewModuleEngine implements the same method as documented on wasm.Engine.
-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)
- 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
-}
-
-// lowerIR lowers the interpreterir operations to engine friendly struct.
-func (e *engine) lowerIR(ir *compilationResult, ret *compiledFunction) error {
- // Copy the body from the result.
- ret.body = make([]unionOperation, len(ir.Operations))
- copy(ret.body, ir.Operations)
- // Also copy the offsets if necessary.
- if offsets := ir.IROperationSourceOffsetsInWasmBinary; len(offsets) > 0 {
- ret.offsetsInWasmBinary = make([]uint64, len(offsets))
- copy(ret.offsetsInWasmBinary, offsets)
- }
-
- labelAddressResolutions := [labelKindNum][]uint64{}
-
- // First, we iterate all labels, and resolve the address.
- 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()]
- // Expand the slice if necessary.
- if diff := fid - len(frameToAddresses) + 1; diff > 0 {
- for j := 0; j < diff; j++ {
- frameToAddresses = append(frameToAddresses, 0)
- }
- }
- frameToAddresses[fid] = address
- labelAddressResolutions[kind] = frameToAddresses
- }
- }
-
- // Then resolve the label as the index to the body.
- 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)
- }
- }
- }
- return nil
-}
-
-func (e *engine) setLabelAddress(op *uint64, label label, labelAddressResolutions [labelKindNum][]uint64) {
- if label.IsReturnTarget() {
- // Jmp to the end of the possible binary.
- *op = math.MaxUint64
- } else {
- *op = labelAddressResolutions[label.Kind()][label.FrameID()]
- }
-}
-
-// ResolveImportedFunction implements wasm.ModuleEngine.
-func (e *moduleEngine) ResolveImportedFunction(index, descFunc, indexInImportedModule wasm.Index, importedModuleEngine wasm.ModuleEngine) {
- imported := importedModuleEngine.(*moduleEngine)
- e.functions[index] = imported.functions[indexInImportedModule]
-}
-
-// ResolveImportedMemory implements wasm.ModuleEngine.
-func (e *moduleEngine) ResolveImportedMemory(wasm.ModuleEngine) {}
-
-// DoneInstantiation implements wasm.ModuleEngine.
-func (e *moduleEngine) DoneInstantiation() {}
-
-// FunctionInstanceReference implements the same method as documented on wasm.ModuleEngine.
-func (e *moduleEngine) FunctionInstanceReference(funcIndex wasm.Index) wasm.Reference {
- return uintptr(unsafe.Pointer(&e.functions[funcIndex]))
-}
-
-// NewFunction implements the same method as documented on wasm.ModuleEngine.
-func (e *moduleEngine) NewFunction(index wasm.Index) (ce api.Function) {
- // Note: The input parameters are pre-validated, so a compiled function is only absent on close. Updates to
- // code on close aren't locked, neither is this read.
- compiled := &e.functions[index]
- return e.newCallEngine(compiled)
-}
-
-// LookupFunction implements the same method as documented on wasm.ModuleEngine.
-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
-}
-
-// Definition implements the same method as documented on api.Function.
-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)
-}
-
-// Call implements the same method as documented on api.Function.
-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)
-}
-
-// CallWithStack implements the same method as documented on api.Function.
-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():
- // If the provided context is already done, close the call context
- // and return the error.
- m.CloseWithCtxErr(ctx)
- return nil, m.FailIfClosed()
- default:
- }
- }
-
- if ctx.Value(expctxkeys.EnableSnapshotterKey{}) != nil {
- ctx = context.WithValue(ctx, expctxkeys.SnapshotterKey{}, ce)
- }
-
- defer func() {
- // If the module closed during the call, and the call didn't err for another reason, set an ExitError.
- if err == nil {
- err = m.FailIfClosed()
- }
- // TODO: ^^ Will not fail if the function was imported from a closed module.
-
- 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)
-
- // This returns a safe copy of the results, instead of a slice view. If we
- // returned a re-slice, the caller could accidentally or purposefully
- // corrupt the stack of subsequent calls.
- ft := ce.f.funcType
- if results == nil && ft.ResultNumInUint64 > 0 {
- results = make([]uint64, ft.ResultNumInUint64)
- }
- ce.popValues(results)
- return results, nil
-}
-
-// functionListenerInvocation captures arguments needed to perform function
-// listener invocations when unwinding the call stack.
-type functionListenerInvocation struct {
- experimental.FunctionListener
- def api.FunctionDefinition
-}
-
-// recoverOnCall takes the recovered value `recoverOnCall`, and wraps it
-// with the call frame stack traces. Also, reset the state of callEngine
-// so that it can be used for the subsequent calls.
-func (ce *callEngine) recoverOnCall(ctx context.Context, m *wasm.ModuleInstance, v interface{}) (err error) {
- if s, ok := v.(*snapshot); ok {
- // A snapshot that wasn't handled was created by a different call engine possibly from a nested wasm invocation,
- // let it propagate up to be handled by the caller.
- 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)
- }
-
- // Allows the reuse of CallEngine.
- 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 {
- // TODO: This doesn't get the error due to use of panic to propagate them.
- 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]
- // TODO: add description of each operation/case
- // on, for example, how many args are used,
- // how the stack is modified, etc.
- 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]
- 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 != typeIDs[op.U1] {
- panic(wasmruntime.ErrRuntimeIndirectCallTypeMismatch)
- }
-
- ce.callFunction(ctx, f.moduleInstance, tf)
- frame.pc++
- case operationKindDrop:
- ce.drop(op.U1)
- frame.pc++
- case operationKindSelect:
- c := ce.popValue()
- if op.B3 { // Target is vector.
- x2Hi, x2Lo := ce.popValue(), ce.popValue()
- if c == 0 {
- _, _ = ce.popValue(), ce.popValue() // discard the x1's lo and hi bits.
- 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 { // V128 value target.
- ce.pushValue(ce.stack[index+1])
- }
- frame.pc++
- case operationKindSet:
- if op.B3 { // V128 value target.
- 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 { // Signed
- 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)) // = -1 in signed 32-bit integer.
- } 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 {
- // unsignedInt32
- ce.pushValue(uint64(bits.LeadingZeros32(uint32(v))))
- } else {
- // unsignedInt64
- ce.pushValue(uint64(bits.LeadingZeros64(v)))
- }
- frame.pc++
- case operationKindCtz:
- v := ce.popValue()
- if op.B1 == 0 {
- // unsignedInt32
- ce.pushValue(uint64(bits.TrailingZeros32(uint32(v))))
- } else {
- // unsignedInt64
- ce.pushValue(uint64(bits.TrailingZeros64(v)))
- }
- frame.pc++
- case operationKindPopcnt:
- v := ce.popValue()
- if op.B1 == 0 {
- // unsignedInt32
- ce.pushValue(uint64(bits.OnesCount32(uint32(v))))
- } else {
- // unsignedInt64
- ce.pushValue(uint64(bits.OnesCount64(v)))
- }
- frame.pc++
- case operationKindDiv:
- // If an integer, check we won't divide by zero.
- t := signedType(op.B1)
- v2, v1 := ce.popValue(), ce.popValue()
- switch t {
- case signedTypeFloat32, signedTypeFloat64: // not integers
- 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 {
- // unsignedInt32
- ce.pushValue(uint64(uint32(v2) & uint32(v1)))
- } else {
- // unsignedInt64
- ce.pushValue(uint64(v2 & v1))
- }
- frame.pc++
- case operationKindOr:
- v2 := ce.popValue()
- v1 := ce.popValue()
- if op.B1 == 0 {
- // unsignedInt32
- ce.pushValue(uint64(uint32(v2) | uint32(v1)))
- } else {
- // unsignedInt64
- ce.pushValue(uint64(v2 | v1))
- }
- frame.pc++
- case operationKindXor:
- v2 := ce.popValue()
- v1 := ce.popValue()
- if op.B1 == 0 {
- // unsignedInt32
- ce.pushValue(uint64(uint32(v2) ^ uint32(v1)))
- } else {
- // unsignedInt64
- ce.pushValue(uint64(v2 ^ v1))
- }
- frame.pc++
- case operationKindShl:
- v2 := ce.popValue()
- v1 := ce.popValue()
- if op.B1 == 0 {
- // unsignedInt32
- ce.pushValue(uint64(uint32(v1) << (uint32(v2) % 32)))
- } else {
- // unsignedInt64
- 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 {
- // unsignedInt32
- ce.pushValue(uint64(bits.RotateLeft32(uint32(v1), int(v2))))
- } else {
- // unsignedInt64
- ce.pushValue(uint64(bits.RotateLeft64(v1, int(v2))))
- }
- frame.pc++
- case operationKindRotr:
- v2 := ce.popValue()
- v1 := ce.popValue()
- if op.B1 == 0 {
- // unsignedInt32
- ce.pushValue(uint64(bits.RotateLeft32(uint32(v1), -int(v2))))
- } else {
- // unsignedInt64
- ce.pushValue(uint64(bits.RotateLeft64(v1, -int(v2))))
- }
- frame.pc++
- case operationKindAbs:
- if op.B1 == 0 {
- // float32
- const mask uint32 = 1 << 31
- ce.pushValue(uint64(uint32(ce.popValue()) &^ mask))
- } else {
- // float64
- const mask uint64 = 1 << 63
- ce.pushValue(ce.popValue() &^ mask)
- }
- frame.pc++
- case operationKindNeg:
- if op.B1 == 0 {
- // float32
- v := -math.Float32frombits(uint32(ce.popValue()))
- ce.pushValue(uint64(math.Float32bits(v)))
- } else {
- // float64
- v := -math.Float64frombits(ce.popValue())
- ce.pushValue(math.Float64bits(v))
- }
- frame.pc++
- case operationKindCeil:
- if op.B1 == 0 {
- // float32
- v := moremath.WasmCompatCeilF32(math.Float32frombits(uint32(ce.popValue())))
- ce.pushValue(uint64(math.Float32bits(v)))
- } else {
- // float64
- v := moremath.WasmCompatCeilF64(math.Float64frombits(ce.popValue()))
- ce.pushValue(math.Float64bits(v))
- }
- frame.pc++
- case operationKindFloor:
- if op.B1 == 0 {
- // float32
- v := moremath.WasmCompatFloorF32(math.Float32frombits(uint32(ce.popValue())))
- ce.pushValue(uint64(math.Float32bits(v)))
- } else {
- // float64
- v := moremath.WasmCompatFloorF64(math.Float64frombits(ce.popValue()))
- ce.pushValue(math.Float64bits(v))
- }
- frame.pc++
- case operationKindTrunc:
- if op.B1 == 0 {
- // float32
- v := moremath.WasmCompatTruncF32(math.Float32frombits(uint32(ce.popValue())))
- ce.pushValue(uint64(math.Float32bits(v)))
- } else {
- // float64
- v := moremath.WasmCompatTruncF64(math.Float64frombits(ce.popValue()))
- ce.pushValue(math.Float64bits(v))
- }
- frame.pc++
- case operationKindNearest:
- if op.B1 == 0 {
- // float32
- f := math.Float32frombits(uint32(ce.popValue()))
- ce.pushValue(uint64(math.Float32bits(moremath.WasmCompatNearestF32(f))))
- } else {
- // float64
- f := math.Float64frombits(ce.popValue())
- ce.pushValue(math.Float64bits(moremath.WasmCompatNearestF64(f)))
- }
- frame.pc++
- case operationKindSqrt:
- if op.B1 == 0 {
- // float32
- v := math.Sqrt(float64(math.Float32frombits(uint32(ce.popValue()))))
- ce.pushValue(uint64(math.Float32bits(float32(v))))
- } else {
- // float64
- v := math.Sqrt(math.Float64frombits(ce.popValue()))
- ce.pushValue(math.Float64bits(v))
- }
- frame.pc++
- case operationKindMin:
- if op.B1 == 0 {
- // float32
- 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 {
- // float64
- 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 {
- // float32
- v2 := uint32(ce.popValue())
- v1 := uint32(ce.popValue())
- const signbit = 1 << 31
- ce.pushValue(uint64(v1&^signbit | v2&signbit))
- } else {
- // float64
- 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 {
- // float32
- switch signedInt(op.B2) {
- case signedInt32:
- v := math.Trunc(float64(math.Float32frombits(uint32(ce.popValue()))))
- if math.IsNaN(v) { // NaN cannot be compared with themselves, so we have to use IsNaN
- if op.B3 {
- // non-trapping conversion must cast nan to zero.
- v = 0
- } else {
- panic(wasmruntime.ErrRuntimeInvalidConversionToInteger)
- }
- } else if v < math.MinInt32 || v > math.MaxInt32 {
- if op.B3 {
- // non-trapping conversion must "saturate" the value for overflowing sources.
- 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) { // NaN cannot be compared with themselves, so we have to use IsNaN
- if op.B3 {
- // non-trapping conversion must cast nan to zero.
- res = 0
- } else {
- panic(wasmruntime.ErrRuntimeInvalidConversionToInteger)
- }
- } else if v < math.MinInt64 || v >= math.MaxInt64 {
- // Note: math.MaxInt64 is rounded up to math.MaxInt64+1 in 64-bit float representation,
- // and that's why we use '>=' not '>' to check overflow.
- if op.B3 {
- // non-trapping conversion must "saturate" the value for overflowing sources.
- 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) { // NaN cannot be compared with themselves, so we have to use IsNaN
- if op.B3 {
- // non-trapping conversion must cast nan to zero.
- v = 0
- } else {
- panic(wasmruntime.ErrRuntimeInvalidConversionToInteger)
- }
- } else if v < 0 || v > math.MaxUint32 {
- if op.B3 {
- // non-trapping conversion must "saturate" the value for overflowing source.
- 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) { // NaN cannot be compared with themselves, so we have to use IsNaN
- if op.B3 {
- // non-trapping conversion must cast nan to zero.
- res = 0
- } else {
- panic(wasmruntime.ErrRuntimeInvalidConversionToInteger)
- }
- } else if v < 0 || v >= math.MaxUint64 {
- // Note: math.MaxUint64 is rounded up to math.MaxUint64+1 in 64-bit float representation,
- // and that's why we use '>=' not '>' to check overflow.
- if op.B3 {
- // non-trapping conversion must "saturate" the value for overflowing source.
- if v < 0 {
- res = 0
- } else {
- res = math.MaxUint64
- }
- } else {
- panic(wasmruntime.ErrRuntimeIntegerOverflow)
- }
- }
- ce.pushValue(res)
- }
- } else {
- // float64
- switch signedInt(op.B2) {
- case signedInt32:
- v := math.Trunc(math.Float64frombits(ce.popValue()))
- if math.IsNaN(v) { // NaN cannot be compared with themselves, so we have to use IsNaN
- if op.B3 {
- // non-trapping conversion must cast nan to zero.
- v = 0
- } else {
- panic(wasmruntime.ErrRuntimeInvalidConversionToInteger)
- }
- } else if v < math.MinInt32 || v > math.MaxInt32 {
- if op.B3 {
- // non-trapping conversion must "saturate" the value for overflowing source.
- 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) { // NaN cannot be compared with themselves, so we have to use IsNaN
- if op.B3 {
- // non-trapping conversion must cast nan to zero.
- res = 0
- } else {
- panic(wasmruntime.ErrRuntimeInvalidConversionToInteger)
- }
- } else if v < math.MinInt64 || v >= math.MaxInt64 {
- // Note: math.MaxInt64 is rounded up to math.MaxInt64+1 in 64-bit float representation,
- // and that's why we use '>=' not '>' to check overflow.
- if op.B3 {
- // non-trapping conversion must "saturate" the value for overflowing source.
- 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) { // NaN cannot be compared with themselves, so we have to use IsNaN
- if op.B3 {
- // non-trapping conversion must cast nan to zero.
- v = 0
- } else {
- panic(wasmruntime.ErrRuntimeInvalidConversionToInteger)
- }
- } else if v < 0 || v > math.MaxUint32 {
- if op.B3 {
- // non-trapping conversion must "saturate" the value for overflowing source.
- 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) { // NaN cannot be compared with themselves, so we have to use IsNaN
- if op.B3 {
- // non-trapping conversion must cast nan to zero.
- res = 0
- } else {
- panic(wasmruntime.ErrRuntimeInvalidConversionToInteger)
- }
- } else if v < 0 || v >= math.MaxUint64 {
- // Note: math.MaxUint64 is rounded up to math.MaxUint64+1 in 64-bit float representation,
- // and that's why we use '>=' not '>' to check overflow.
- if op.B3 {
- // non-trapping conversion must "saturate" the value for overflowing source.
- 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 {
- // float32
- v := float32(int32(ce.popValue()))
- ce.pushValue(uint64(math.Float32bits(v)))
- } else {
- // float64
- v := float64(int32(ce.popValue()))
- ce.pushValue(math.Float64bits(v))
- }
- case signedInt64:
- if op.B2 == 0 {
- // float32
- v := float32(int64(ce.popValue()))
- ce.pushValue(uint64(math.Float32bits(v)))
- } else {
- // float64
- v := float64(int64(ce.popValue()))
- ce.pushValue(math.Float64bits(v))
- }
- case signedUint32:
- if op.B2 == 0 {
- // float32
- v := float32(uint32(ce.popValue()))
- ce.pushValue(uint64(math.Float32bits(v)))
- } else {
- // float64
- v := float64(uint32(ce.popValue()))
- ce.pushValue(math.Float64bits(v))
- }
- case signedUint64:
- if op.B2 == 0 {
- // float32
- v := float32(ce.popValue())
- ce.pushValue(uint64(math.Float32bits(v)))
- } else {
- // float64
- 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 {
- // Signed.
- 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 {
- // Uses the copy trick for faster filling buffer.
- // https://gist.github.com/taylorza/df2f89d5f9ab3ffd06865062a4cf015d
- buf := memoryInst.Buffer[offset : offset+fillSize]
- buf[0] = value
- for i := 1; i < len(buf); i *= 2 {
- copy(buf[i:], buf[:i])
- }
- }
- 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) // externrefs are opaque uint64.
- 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 {
- // Uses the copy trick for faster filling the region with the value.
- // https://gist.github.com/taylorza/df2f89d5f9ab3ffd06865062a4cf015d
- 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)
- // Write the upper bytes first to trigger an early error if the memory access is out of bounds.
- // Otherwise, the lower bytes might be written to memory, but the upper bytes might not.
- 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 {
- // sign-extend.
- 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 {
- // sign-extend.
- 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:
- // https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md#bitmask-extraction
- 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:
- // https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md#bitwise-select
- cHi, cLo := ce.popValue(), ce.popValue()
- x2Hi, x2Lo := ce.popValue(), ce.popValue()
- x1Hi, x1Lo := ce.popValue(), ce.popValue()
- // v128.or(v128.and(v1, c), v128.and(v2, v128.not(c)))
- 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 { // signed
- 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 { // signed
- 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 { // signed
- 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
-
- // Lane-wise addition while saturating the overflowing values.
- // https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md#saturating-integer-addition
- 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 { // signed
- 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 { // first 8 lanes are on lower 64bits.
- 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 { // signed
- 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 { // first 4 lanes are on lower 64bits.
- 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
-
- // Lane-wise subtraction while saturating the overflowing values.
- // https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md#saturating-integer-subtraction
- 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 { // signed
- 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 { // signed
- 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 { // signed
- 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 { // signed
- 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 { // signed
- 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 { // signed
- 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 { // signed
- 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 { // signed
- 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 { // use lower 64 bits
- 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 { // use lower 64 bits
- 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
- // https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md#saturating-integer-q-format-rounding-multiplication
- 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 { // Destination shape.
- case shapeF32x4: // f32x4 from signed/unsigned i32x4
- 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: // f64x2 from signed/unsigned i32x4
- 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: // signed/unsigned i16x8 to i8x16
- 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: // signed/unsigned i32x4 to i16x8
- 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: // f32x4 to i32x4
- 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: // f64x2 to i32x4
- 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)
- // Runtime instead of validation error because the spec intends to allow binaries to include
- // such instructions as long as they are not executed.
- 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)
- }
- // Just a bounds check
- if offset >= memoryInst.Size() {
- panic(wasmruntime.ErrRuntimeOutOfBoundsMemoryAccess)
- }
- res := memoryInst.Notify(offset, uint32(count))
- ce.pushValue(uint64(res))
- frame.pc++
- case operationKindAtomicFence:
- // Memory not required for fence only
- if memoryInst != nil {
- // An empty critical section can be used as a synchronization primitive, which is what
- // fence is. Probably, there are no spectests or defined behavior to confirm this yet.
- memoryInst.Mux.Lock()
- memoryInst.Mux.Unlock() //nolint:staticcheck
- }
- 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++
- default:
- frame.pc++
- }
- }
- ce.popFrame()
-}
-
-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)))
-}
-
-// https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/exec/numerics.html#xref-exec-numerics-op-flt-mathrm-flt-n-z-1-z-2
-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
-}
-
-// https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/exec/numerics.html#xref-exec-numerics-op-flt-mathrm-flt-n-z-1-z-2
-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 {
- // https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md#lane-wise-integer-rounding-average
- return byte((uint16(v1) + uint16(v2) + uint16(1)) / 2)
-}
-
-func i16RoundingAverage(v1, v2 uint16) uint16 {
- // https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/simd/SIMD.md#lane-wise-integer-rounding-average
- 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
-}
-
-// popMemoryOffset takes a memory offset off the stack for use in load and store instructions.
-// As the top of stack value is 64-bit, this ensures it is in range before returning it.
-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
-
- // In the interpreter engine, ce.stack may only have capacity to store
- // parameters. Grow when there are more results than parameters.
- if growLen := resultLen - paramLen; growLen > 0 {
- for i := 0; i < growLen; i++ {
- ce.stack = append(ce.stack, 0)
- }
- stackLen += growLen
- }
-
- // Pass the stack elements to the go function.
- stack := ce.stack[len(ce.stack)-stackLen:]
- ce.callGoFunc(ctx, m, f, stack)
-
- // Shrink the stack when there were more parameters than results.
- if shrinkLen := paramLen - resultLen; shrinkLen > 0 {
- ce.stack = ce.stack[0 : len(ce.stack)-shrinkLen]
- }
-}
-
-// v128Dot performs a dot product of two 64-bit vectors.
-// Note: for some reason (which I suspect is due to a bug in Go compiler's regalloc),
-// inlining this function causes a bug which happens **only when** we run with -race AND arm64 AND Go 1.22.
-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)
-}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/operations.go b/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/operations.go
deleted file mode 100644
index 3087a718f..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/operations.go
+++ /dev/null
@@ -1,2812 +0,0 @@
-package interpreter
-
-import (
- "fmt"
- "math"
- "strings"
-)
-
-// unsignedInt represents unsigned 32-bit or 64-bit integers.
-type unsignedInt byte
-
-const (
- unsignedInt32 unsignedInt = iota
- unsignedInt64
-)
-
-// String implements fmt.Stringer.
-func (s unsignedInt) String() (ret string) {
- switch s {
- case unsignedInt32:
- ret = "i32"
- case unsignedInt64:
- ret = "i64"
- }
- return
-}
-
-// signedInt represents signed or unsigned integers.
-type signedInt byte
-
-const (
- signedInt32 signedInt = iota
- signedInt64
- signedUint32
- signedUint64
-)
-
-// String implements fmt.Stringer.
-func (s signedInt) String() (ret string) {
- switch s {
- case signedUint32:
- ret = "u32"
- case signedUint64:
- ret = "u64"
- case signedInt32:
- ret = "s32"
- case signedInt64:
- ret = "s64"
- }
- return
-}
-
-// float represents the scalar double or single precision floating points.
-type float byte
-
-const (
- f32 float = iota
- f64
-)
-
-// String implements fmt.Stringer.
-func (s float) String() (ret string) {
- switch s {
- case f32:
- ret = "f32"
- case f64:
- ret = "f64"
- }
- return
-}
-
-// unsignedType is the union of unsignedInt, float and V128 vector type.
-type unsignedType byte
-
-const (
- unsignedTypeI32 unsignedType = iota
- unsignedTypeI64
- unsignedTypeF32
- unsignedTypeF64
- unsignedTypeV128
- unsignedTypeUnknown
-)
-
-// String implements fmt.Stringer.
-func (s unsignedType) String() (ret string) {
- switch s {
- case unsignedTypeI32:
- ret = "i32"
- case unsignedTypeI64:
- ret = "i64"
- case unsignedTypeF32:
- ret = "f32"
- case unsignedTypeF64:
- ret = "f64"
- case unsignedTypeV128:
- ret = "v128"
- case unsignedTypeUnknown:
- ret = "unknown"
- }
- return
-}
-
-// signedType is the union of signedInt and float types.
-type signedType byte
-
-const (
- signedTypeInt32 signedType = iota
- signedTypeUint32
- signedTypeInt64
- signedTypeUint64
- signedTypeFloat32
- signedTypeFloat64
-)
-
-// String implements fmt.Stringer.
-func (s signedType) String() (ret string) {
- switch s {
- case signedTypeInt32:
- ret = "s32"
- case signedTypeUint32:
- ret = "u32"
- case signedTypeInt64:
- ret = "s64"
- case signedTypeUint64:
- ret = "u64"
- case signedTypeFloat32:
- ret = "f32"
- case signedTypeFloat64:
- ret = "f64"
- }
- return
-}
-
-// operationKind is the Kind of each implementation of Operation interface.
-type operationKind uint16
-
-// String implements fmt.Stringer.
-func (o operationKind) String() (ret string) {
- switch o {
- case operationKindUnreachable:
- ret = "Unreachable"
- case operationKindLabel:
- ret = "label"
- case operationKindBr:
- ret = "Br"
- case operationKindBrIf:
- ret = "BrIf"
- case operationKindBrTable:
- ret = "BrTable"
- case operationKindCall:
- ret = "Call"
- case operationKindCallIndirect:
- ret = "CallIndirect"
- case operationKindDrop:
- ret = "Drop"
- case operationKindSelect:
- ret = "Select"
- case operationKindPick:
- ret = "Pick"
- case operationKindSet:
- ret = "Swap"
- case operationKindGlobalGet:
- ret = "GlobalGet"
- case operationKindGlobalSet:
- ret = "GlobalSet"
- case operationKindLoad:
- ret = "Load"
- case operationKindLoad8:
- ret = "Load8"
- case operationKindLoad16:
- ret = "Load16"
- case operationKindLoad32:
- ret = "Load32"
- case operationKindStore:
- ret = "Store"
- case operationKindStore8:
- ret = "Store8"
- case operationKindStore16:
- ret = "Store16"
- case operationKindStore32:
- ret = "Store32"
- case operationKindMemorySize:
- ret = "MemorySize"
- case operationKindMemoryGrow:
- ret = "MemoryGrow"
- case operationKindConstI32:
- ret = "ConstI32"
- case operationKindConstI64:
- ret = "ConstI64"
- case operationKindConstF32:
- ret = "ConstF32"
- case operationKindConstF64:
- ret = "ConstF64"
- case operationKindEq:
- ret = "Eq"
- case operationKindNe:
- ret = "Ne"
- case operationKindEqz:
- ret = "Eqz"
- case operationKindLt:
- ret = "Lt"
- case operationKindGt:
- ret = "Gt"
- case operationKindLe:
- ret = "Le"
- case operationKindGe:
- ret = "Ge"
- case operationKindAdd:
- ret = "Add"
- case operationKindSub:
- ret = "Sub"
- case operationKindMul:
- ret = "Mul"
- case operationKindClz:
- ret = "Clz"
- case operationKindCtz:
- ret = "Ctz"
- case operationKindPopcnt:
- ret = "Popcnt"
- case operationKindDiv:
- ret = "Div"
- case operationKindRem:
- ret = "Rem"
- case operationKindAnd:
- ret = "And"
- case operationKindOr:
- ret = "Or"
- case operationKindXor:
- ret = "Xor"
- case operationKindShl:
- ret = "Shl"
- case operationKindShr:
- ret = "Shr"
- case operationKindRotl:
- ret = "Rotl"
- case operationKindRotr:
- ret = "Rotr"
- case operationKindAbs:
- ret = "Abs"
- case operationKindNeg:
- ret = "Neg"
- case operationKindCeil:
- ret = "Ceil"
- case operationKindFloor:
- ret = "Floor"
- case operationKindTrunc:
- ret = "Trunc"
- case operationKindNearest:
- ret = "Nearest"
- case operationKindSqrt:
- ret = "Sqrt"
- case operationKindMin:
- ret = "Min"
- case operationKindMax:
- ret = "Max"
- case operationKindCopysign:
- ret = "Copysign"
- case operationKindI32WrapFromI64:
- ret = "I32WrapFromI64"
- case operationKindITruncFromF:
- ret = "ITruncFromF"
- case operationKindFConvertFromI:
- ret = "FConvertFromI"
- case operationKindF32DemoteFromF64:
- ret = "F32DemoteFromF64"
- case operationKindF64PromoteFromF32:
- ret = "F64PromoteFromF32"
- case operationKindI32ReinterpretFromF32:
- ret = "I32ReinterpretFromF32"
- case operationKindI64ReinterpretFromF64:
- ret = "I64ReinterpretFromF64"
- case operationKindF32ReinterpretFromI32:
- ret = "F32ReinterpretFromI32"
- case operationKindF64ReinterpretFromI64:
- ret = "F64ReinterpretFromI64"
- case operationKindExtend:
- ret = "Extend"
- case operationKindMemoryInit:
- ret = "MemoryInit"
- case operationKindDataDrop:
- ret = "DataDrop"
- case operationKindMemoryCopy:
- ret = "MemoryCopy"
- case operationKindMemoryFill:
- ret = "MemoryFill"
- case operationKindTableInit:
- ret = "TableInit"
- case operationKindElemDrop:
- ret = "ElemDrop"
- case operationKindTableCopy:
- ret = "TableCopy"
- case operationKindRefFunc:
- ret = "RefFunc"
- case operationKindTableGet:
- ret = "TableGet"
- case operationKindTableSet:
- ret = "TableSet"
- case operationKindTableSize:
- ret = "TableSize"
- case operationKindTableGrow:
- ret = "TableGrow"
- case operationKindTableFill:
- ret = "TableFill"
- case operationKindV128Const:
- ret = "ConstV128"
- case operationKindV128Add:
- ret = "V128Add"
- case operationKindV128Sub:
- ret = "V128Sub"
- case operationKindV128Load:
- ret = "V128Load"
- case operationKindV128LoadLane:
- ret = "V128LoadLane"
- case operationKindV128Store:
- ret = "V128Store"
- case operationKindV128StoreLane:
- ret = "V128StoreLane"
- case operationKindV128ExtractLane:
- ret = "V128ExtractLane"
- case operationKindV128ReplaceLane:
- ret = "V128ReplaceLane"
- case operationKindV128Splat:
- ret = "V128Splat"
- case operationKindV128Shuffle:
- ret = "V128Shuffle"
- case operationKindV128Swizzle:
- ret = "V128Swizzle"
- case operationKindV128AnyTrue:
- ret = "V128AnyTrue"
- case operationKindV128AllTrue:
- ret = "V128AllTrue"
- case operationKindV128And:
- ret = "V128And"
- case operationKindV128Not:
- ret = "V128Not"
- case operationKindV128Or:
- ret = "V128Or"
- case operationKindV128Xor:
- ret = "V128Xor"
- case operationKindV128Bitselect:
- ret = "V128Bitselect"
- case operationKindV128AndNot:
- ret = "V128AndNot"
- case operationKindV128BitMask:
- ret = "V128BitMask"
- case operationKindV128Shl:
- ret = "V128Shl"
- case operationKindV128Shr:
- ret = "V128Shr"
- case operationKindV128Cmp:
- ret = "V128Cmp"
- case operationKindSignExtend32From8:
- ret = "SignExtend32From8"
- case operationKindSignExtend32From16:
- ret = "SignExtend32From16"
- case operationKindSignExtend64From8:
- ret = "SignExtend64From8"
- case operationKindSignExtend64From16:
- ret = "SignExtend64From16"
- case operationKindSignExtend64From32:
- ret = "SignExtend64From32"
- case operationKindV128AddSat:
- ret = "V128AddSat"
- case operationKindV128SubSat:
- ret = "V128SubSat"
- case operationKindV128Mul:
- ret = "V128Mul"
- case operationKindV128Div:
- ret = "V128Div"
- case operationKindV128Neg:
- ret = "V128Neg"
- case operationKindV128Sqrt:
- ret = "V128Sqrt"
- case operationKindV128Abs:
- ret = "V128Abs"
- case operationKindV128Popcnt:
- ret = "V128Popcnt"
- case operationKindV128Min:
- ret = "V128Min"
- case operationKindV128Max:
- ret = "V128Max"
- case operationKindV128AvgrU:
- ret = "V128AvgrU"
- case operationKindV128Ceil:
- ret = "V128Ceil"
- case operationKindV128Floor:
- ret = "V128Floor"
- case operationKindV128Trunc:
- ret = "V128Trunc"
- case operationKindV128Nearest:
- ret = "V128Nearest"
- case operationKindV128Pmin:
- ret = "V128Pmin"
- case operationKindV128Pmax:
- ret = "V128Pmax"
- case operationKindV128Extend:
- ret = "V128Extend"
- case operationKindV128ExtMul:
- ret = "V128ExtMul"
- case operationKindV128Q15mulrSatS:
- ret = "V128Q15mulrSatS"
- case operationKindV128ExtAddPairwise:
- ret = "V128ExtAddPairwise"
- case operationKindV128FloatPromote:
- ret = "V128FloatPromote"
- case operationKindV128FloatDemote:
- ret = "V128FloatDemote"
- case operationKindV128FConvertFromI:
- ret = "V128FConvertFromI"
- case operationKindV128Dot:
- ret = "V128Dot"
- case operationKindV128Narrow:
- ret = "V128Narrow"
- case operationKindV128ITruncSatFromF:
- ret = "V128ITruncSatFromF"
- case operationKindBuiltinFunctionCheckExitCode:
- ret = "BuiltinFunctionCheckExitCode"
- case operationKindAtomicMemoryWait:
- ret = "operationKindAtomicMemoryWait"
- case operationKindAtomicMemoryNotify:
- ret = "operationKindAtomicMemoryNotify"
- case operationKindAtomicFence:
- ret = "operationKindAtomicFence"
- case operationKindAtomicLoad:
- ret = "operationKindAtomicLoad"
- case operationKindAtomicLoad8:
- ret = "operationKindAtomicLoad8"
- case operationKindAtomicLoad16:
- ret = "operationKindAtomicLoad16"
- case operationKindAtomicStore:
- ret = "operationKindAtomicStore"
- case operationKindAtomicStore8:
- ret = "operationKindAtomicStore8"
- case operationKindAtomicStore16:
- ret = "operationKindAtomicStore16"
- case operationKindAtomicRMW:
- ret = "operationKindAtomicRMW"
- case operationKindAtomicRMW8:
- ret = "operationKindAtomicRMW8"
- case operationKindAtomicRMW16:
- ret = "operationKindAtomicRMW16"
- case operationKindAtomicRMWCmpxchg:
- ret = "operationKindAtomicRMWCmpxchg"
- case operationKindAtomicRMW8Cmpxchg:
- ret = "operationKindAtomicRMW8Cmpxchg"
- case operationKindAtomicRMW16Cmpxchg:
- ret = "operationKindAtomicRMW16Cmpxchg"
- default:
- panic(fmt.Errorf("unknown operation %d", o))
- }
- return
-}
-
-const (
- // operationKindUnreachable is the Kind for NewOperationUnreachable.
- operationKindUnreachable operationKind = iota
- // operationKindLabel is the Kind for NewOperationLabel.
- operationKindLabel
- // operationKindBr is the Kind for NewOperationBr.
- operationKindBr
- // operationKindBrIf is the Kind for NewOperationBrIf.
- operationKindBrIf
- // operationKindBrTable is the Kind for NewOperationBrTable.
- operationKindBrTable
- // operationKindCall is the Kind for NewOperationCall.
- operationKindCall
- // operationKindCallIndirect is the Kind for NewOperationCallIndirect.
- operationKindCallIndirect
- // operationKindDrop is the Kind for NewOperationDrop.
- operationKindDrop
- // operationKindSelect is the Kind for NewOperationSelect.
- operationKindSelect
- // operationKindPick is the Kind for NewOperationPick.
- operationKindPick
- // operationKindSet is the Kind for NewOperationSet.
- operationKindSet
- // operationKindGlobalGet is the Kind for NewOperationGlobalGet.
- operationKindGlobalGet
- // operationKindGlobalSet is the Kind for NewOperationGlobalSet.
- operationKindGlobalSet
- // operationKindLoad is the Kind for NewOperationLoad.
- operationKindLoad
- // operationKindLoad8 is the Kind for NewOperationLoad8.
- operationKindLoad8
- // operationKindLoad16 is the Kind for NewOperationLoad16.
- operationKindLoad16
- // operationKindLoad32 is the Kind for NewOperationLoad32.
- operationKindLoad32
- // operationKindStore is the Kind for NewOperationStore.
- operationKindStore
- // operationKindStore8 is the Kind for NewOperationStore8.
- operationKindStore8
- // operationKindStore16 is the Kind for NewOperationStore16.
- operationKindStore16
- // operationKindStore32 is the Kind for NewOperationStore32.
- operationKindStore32
- // operationKindMemorySize is the Kind for NewOperationMemorySize.
- operationKindMemorySize
- // operationKindMemoryGrow is the Kind for NewOperationMemoryGrow.
- operationKindMemoryGrow
- // operationKindConstI32 is the Kind for NewOperationConstI32.
- operationKindConstI32
- // operationKindConstI64 is the Kind for NewOperationConstI64.
- operationKindConstI64
- // operationKindConstF32 is the Kind for NewOperationConstF32.
- operationKindConstF32
- // operationKindConstF64 is the Kind for NewOperationConstF64.
- operationKindConstF64
- // operationKindEq is the Kind for NewOperationEq.
- operationKindEq
- // operationKindNe is the Kind for NewOperationNe.
- operationKindNe
- // operationKindEqz is the Kind for NewOperationEqz.
- operationKindEqz
- // operationKindLt is the Kind for NewOperationLt.
- operationKindLt
- // operationKindGt is the Kind for NewOperationGt.
- operationKindGt
- // operationKindLe is the Kind for NewOperationLe.
- operationKindLe
- // operationKindGe is the Kind for NewOperationGe.
- operationKindGe
- // operationKindAdd is the Kind for NewOperationAdd.
- operationKindAdd
- // operationKindSub is the Kind for NewOperationSub.
- operationKindSub
- // operationKindMul is the Kind for NewOperationMul.
- operationKindMul
- // operationKindClz is the Kind for NewOperationClz.
- operationKindClz
- // operationKindCtz is the Kind for NewOperationCtz.
- operationKindCtz
- // operationKindPopcnt is the Kind for NewOperationPopcnt.
- operationKindPopcnt
- // operationKindDiv is the Kind for NewOperationDiv.
- operationKindDiv
- // operationKindRem is the Kind for NewOperationRem.
- operationKindRem
- // operationKindAnd is the Kind for NewOperationAnd.
- operationKindAnd
- // operationKindOr is the Kind for NewOperationOr.
- operationKindOr
- // operationKindXor is the Kind for NewOperationXor.
- operationKindXor
- // operationKindShl is the Kind for NewOperationShl.
- operationKindShl
- // operationKindShr is the Kind for NewOperationShr.
- operationKindShr
- // operationKindRotl is the Kind for NewOperationRotl.
- operationKindRotl
- // operationKindRotr is the Kind for NewOperationRotr.
- operationKindRotr
- // operationKindAbs is the Kind for NewOperationAbs.
- operationKindAbs
- // operationKindNeg is the Kind for NewOperationNeg.
- operationKindNeg
- // operationKindCeil is the Kind for NewOperationCeil.
- operationKindCeil
- // operationKindFloor is the Kind for NewOperationFloor.
- operationKindFloor
- // operationKindTrunc is the Kind for NewOperationTrunc.
- operationKindTrunc
- // operationKindNearest is the Kind for NewOperationNearest.
- operationKindNearest
- // operationKindSqrt is the Kind for NewOperationSqrt.
- operationKindSqrt
- // operationKindMin is the Kind for NewOperationMin.
- operationKindMin
- // operationKindMax is the Kind for NewOperationMax.
- operationKindMax
- // operationKindCopysign is the Kind for NewOperationCopysign.
- operationKindCopysign
- // operationKindI32WrapFromI64 is the Kind for NewOperationI32WrapFromI64.
- operationKindI32WrapFromI64
- // operationKindITruncFromF is the Kind for NewOperationITruncFromF.
- operationKindITruncFromF
- // operationKindFConvertFromI is the Kind for NewOperationFConvertFromI.
- operationKindFConvertFromI
- // operationKindF32DemoteFromF64 is the Kind for NewOperationF32DemoteFromF64.
- operationKindF32DemoteFromF64
- // operationKindF64PromoteFromF32 is the Kind for NewOperationF64PromoteFromF32.
- operationKindF64PromoteFromF32
- // operationKindI32ReinterpretFromF32 is the Kind for NewOperationI32ReinterpretFromF32.
- operationKindI32ReinterpretFromF32
- // operationKindI64ReinterpretFromF64 is the Kind for NewOperationI64ReinterpretFromF64.
- operationKindI64ReinterpretFromF64
- // operationKindF32ReinterpretFromI32 is the Kind for NewOperationF32ReinterpretFromI32.
- operationKindF32ReinterpretFromI32
- // operationKindF64ReinterpretFromI64 is the Kind for NewOperationF64ReinterpretFromI64.
- operationKindF64ReinterpretFromI64
- // operationKindExtend is the Kind for NewOperationExtend.
- operationKindExtend
- // operationKindSignExtend32From8 is the Kind for NewOperationSignExtend32From8.
- operationKindSignExtend32From8
- // operationKindSignExtend32From16 is the Kind for NewOperationSignExtend32From16.
- operationKindSignExtend32From16
- // operationKindSignExtend64From8 is the Kind for NewOperationSignExtend64From8.
- operationKindSignExtend64From8
- // operationKindSignExtend64From16 is the Kind for NewOperationSignExtend64From16.
- operationKindSignExtend64From16
- // operationKindSignExtend64From32 is the Kind for NewOperationSignExtend64From32.
- operationKindSignExtend64From32
- // operationKindMemoryInit is the Kind for NewOperationMemoryInit.
- operationKindMemoryInit
- // operationKindDataDrop is the Kind for NewOperationDataDrop.
- operationKindDataDrop
- // operationKindMemoryCopy is the Kind for NewOperationMemoryCopy.
- operationKindMemoryCopy
- // operationKindMemoryFill is the Kind for NewOperationMemoryFill.
- operationKindMemoryFill
- // operationKindTableInit is the Kind for NewOperationTableInit.
- operationKindTableInit
- // operationKindElemDrop is the Kind for NewOperationElemDrop.
- operationKindElemDrop
- // operationKindTableCopy is the Kind for NewOperationTableCopy.
- operationKindTableCopy
- // operationKindRefFunc is the Kind for NewOperationRefFunc.
- operationKindRefFunc
- // operationKindTableGet is the Kind for NewOperationTableGet.
- operationKindTableGet
- // operationKindTableSet is the Kind for NewOperationTableSet.
- operationKindTableSet
- // operationKindTableSize is the Kind for NewOperationTableSize.
- operationKindTableSize
- // operationKindTableGrow is the Kind for NewOperationTableGrow.
- operationKindTableGrow
- // operationKindTableFill is the Kind for NewOperationTableFill.
- operationKindTableFill
-
- // Vector value related instructions are prefixed by V128.
-
- // operationKindV128Const is the Kind for NewOperationV128Const.
- operationKindV128Const
- // operationKindV128Add is the Kind for NewOperationV128Add.
- operationKindV128Add
- // operationKindV128Sub is the Kind for NewOperationV128Sub.
- operationKindV128Sub
- // operationKindV128Load is the Kind for NewOperationV128Load.
- operationKindV128Load
- // operationKindV128LoadLane is the Kind for NewOperationV128LoadLane.
- operationKindV128LoadLane
- // operationKindV128Store is the Kind for NewOperationV128Store.
- operationKindV128Store
- // operationKindV128StoreLane is the Kind for NewOperationV128StoreLane.
- operationKindV128StoreLane
- // operationKindV128ExtractLane is the Kind for NewOperationV128ExtractLane.
- operationKindV128ExtractLane
- // operationKindV128ReplaceLane is the Kind for NewOperationV128ReplaceLane.
- operationKindV128ReplaceLane
- // operationKindV128Splat is the Kind for NewOperationV128Splat.
- operationKindV128Splat
- // operationKindV128Shuffle is the Kind for NewOperationV128Shuffle.
- operationKindV128Shuffle
- // operationKindV128Swizzle is the Kind for NewOperationV128Swizzle.
- operationKindV128Swizzle
- // operationKindV128AnyTrue is the Kind for NewOperationV128AnyTrue.
- operationKindV128AnyTrue
- // operationKindV128AllTrue is the Kind for NewOperationV128AllTrue.
- operationKindV128AllTrue
- // operationKindV128BitMask is the Kind for NewOperationV128BitMask.
- operationKindV128BitMask
- // operationKindV128And is the Kind for NewOperationV128And.
- operationKindV128And
- // operationKindV128Not is the Kind for NewOperationV128Not.
- operationKindV128Not
- // operationKindV128Or is the Kind for NewOperationV128Or.
- operationKindV128Or
- // operationKindV128Xor is the Kind for NewOperationV128Xor.
- operationKindV128Xor
- // operationKindV128Bitselect is the Kind for NewOperationV128Bitselect.
- operationKindV128Bitselect
- // operationKindV128AndNot is the Kind for NewOperationV128AndNot.
- operationKindV128AndNot
- // operationKindV128Shl is the Kind for NewOperationV128Shl.
- operationKindV128Shl
- // operationKindV128Shr is the Kind for NewOperationV128Shr.
- operationKindV128Shr
- // operationKindV128Cmp is the Kind for NewOperationV128Cmp.
- operationKindV128Cmp
- // operationKindV128AddSat is the Kind for NewOperationV128AddSat.
- operationKindV128AddSat
- // operationKindV128SubSat is the Kind for NewOperationV128SubSat.
- operationKindV128SubSat
- // operationKindV128Mul is the Kind for NewOperationV128Mul.
- operationKindV128Mul
- // operationKindV128Div is the Kind for NewOperationV128Div.
- operationKindV128Div
- // operationKindV128Neg is the Kind for NewOperationV128Neg.
- operationKindV128Neg
- // operationKindV128Sqrt is the Kind for NewOperationV128Sqrt.
- operationKindV128Sqrt
- // operationKindV128Abs is the Kind for NewOperationV128Abs.
- operationKindV128Abs
- // operationKindV128Popcnt is the Kind for NewOperationV128Popcnt.
- operationKindV128Popcnt
- // operationKindV128Min is the Kind for NewOperationV128Min.
- operationKindV128Min
- // operationKindV128Max is the Kind for NewOperationV128Max.
- operationKindV128Max
- // operationKindV128AvgrU is the Kind for NewOperationV128AvgrU.
- operationKindV128AvgrU
- // operationKindV128Pmin is the Kind for NewOperationV128Pmin.
- operationKindV128Pmin
- // operationKindV128Pmax is the Kind for NewOperationV128Pmax.
- operationKindV128Pmax
- // operationKindV128Ceil is the Kind for NewOperationV128Ceil.
- operationKindV128Ceil
- // operationKindV128Floor is the Kind for NewOperationV128Floor.
- operationKindV128Floor
- // operationKindV128Trunc is the Kind for NewOperationV128Trunc.
- operationKindV128Trunc
- // operationKindV128Nearest is the Kind for NewOperationV128Nearest.
- operationKindV128Nearest
- // operationKindV128Extend is the Kind for NewOperationV128Extend.
- operationKindV128Extend
- // operationKindV128ExtMul is the Kind for NewOperationV128ExtMul.
- operationKindV128ExtMul
- // operationKindV128Q15mulrSatS is the Kind for NewOperationV128Q15mulrSatS.
- operationKindV128Q15mulrSatS
- // operationKindV128ExtAddPairwise is the Kind for NewOperationV128ExtAddPairwise.
- operationKindV128ExtAddPairwise
- // operationKindV128FloatPromote is the Kind for NewOperationV128FloatPromote.
- operationKindV128FloatPromote
- // operationKindV128FloatDemote is the Kind for NewOperationV128FloatDemote.
- operationKindV128FloatDemote
- // operationKindV128FConvertFromI is the Kind for NewOperationV128FConvertFromI.
- operationKindV128FConvertFromI
- // operationKindV128Dot is the Kind for NewOperationV128Dot.
- operationKindV128Dot
- // operationKindV128Narrow is the Kind for NewOperationV128Narrow.
- operationKindV128Narrow
- // operationKindV128ITruncSatFromF is the Kind for NewOperationV128ITruncSatFromF.
- operationKindV128ITruncSatFromF
-
- // operationKindBuiltinFunctionCheckExitCode is the Kind for NewOperationBuiltinFunctionCheckExitCode.
- operationKindBuiltinFunctionCheckExitCode
-
- // operationKindAtomicMemoryWait is the kind for NewOperationAtomicMemoryWait.
- operationKindAtomicMemoryWait
- // operationKindAtomicMemoryNotify is the kind for NewOperationAtomicMemoryNotify.
- operationKindAtomicMemoryNotify
- // operationKindAtomicFence is the kind for NewOperationAtomicFence.
- operationKindAtomicFence
- // operationKindAtomicLoad is the kind for NewOperationAtomicLoad.
- operationKindAtomicLoad
- // operationKindAtomicLoad8 is the kind for NewOperationAtomicLoad8.
- operationKindAtomicLoad8
- // operationKindAtomicLoad16 is the kind for NewOperationAtomicLoad16.
- operationKindAtomicLoad16
- // operationKindAtomicStore is the kind for NewOperationAtomicStore.
- operationKindAtomicStore
- // operationKindAtomicStore8 is the kind for NewOperationAtomicStore8.
- operationKindAtomicStore8
- // operationKindAtomicStore16 is the kind for NewOperationAtomicStore16.
- operationKindAtomicStore16
-
- // operationKindAtomicRMW is the kind for NewOperationAtomicRMW.
- operationKindAtomicRMW
- // operationKindAtomicRMW8 is the kind for NewOperationAtomicRMW8.
- operationKindAtomicRMW8
- // operationKindAtomicRMW16 is the kind for NewOperationAtomicRMW16.
- operationKindAtomicRMW16
-
- // operationKindAtomicRMWCmpxchg is the kind for NewOperationAtomicRMWCmpxchg.
- operationKindAtomicRMWCmpxchg
- // operationKindAtomicRMW8Cmpxchg is the kind for NewOperationAtomicRMW8Cmpxchg.
- operationKindAtomicRMW8Cmpxchg
- // operationKindAtomicRMW16Cmpxchg is the kind for NewOperationAtomicRMW16Cmpxchg.
- operationKindAtomicRMW16Cmpxchg
-
- // operationKindEnd is always placed at the bottom of this iota definition to be used in the test.
- operationKindEnd
-)
-
-// NewOperationBuiltinFunctionCheckExitCode is a constructor for unionOperation with Kind operationKindBuiltinFunctionCheckExitCode.
-//
-// OperationBuiltinFunctionCheckExitCode corresponds to the instruction to check the api.Module is already closed due to
-// context.DeadlineExceeded, context.Canceled, or the explicit call of CloseWithExitCode on api.Module.
-func newOperationBuiltinFunctionCheckExitCode() unionOperation {
- return unionOperation{Kind: operationKindBuiltinFunctionCheckExitCode}
-}
-
-// label is the unique identifier for each block in a single function in interpreterir
-// where "block" consists of multiple operations, and must End with branching operations
-// (e.g. operationKindBr or operationKindBrIf).
-type label uint64
-
-// Kind returns the labelKind encoded in this label.
-func (l label) Kind() labelKind {
- return labelKind(uint32(l))
-}
-
-// FrameID returns the frame id encoded in this label.
-func (l label) FrameID() int {
- return int(uint32(l >> 32))
-}
-
-// NewLabel is a constructor for a label.
-func newLabel(kind labelKind, frameID uint32) label {
- return label(kind) | label(frameID)<<32
-}
-
-// String implements fmt.Stringer.
-func (l label) String() (ret string) {
- frameID := l.FrameID()
- switch l.Kind() {
- case labelKindHeader:
- ret = fmt.Sprintf(".L%d", frameID)
- case labelKindElse:
- ret = fmt.Sprintf(".L%d_else", frameID)
- case labelKindContinuation:
- ret = fmt.Sprintf(".L%d_cont", frameID)
- case labelKindReturn:
- return ".return"
- }
- return
-}
-
-func (l label) IsReturnTarget() bool {
- return l.Kind() == labelKindReturn
-}
-
-// labelKind is the Kind of the label.
-type labelKind = byte
-
-const (
- // labelKindHeader is the header for various blocks. For example, the "then" block of
- // wasm.OpcodeIfName in Wasm has the label of this Kind.
- labelKindHeader labelKind = iota
- // labelKindElse is the Kind of label for "else" block of wasm.OpcodeIfName in Wasm.
- labelKindElse
- // labelKindContinuation is the Kind of label which is the continuation of blocks.
- // For example, for wasm text like
- // (func
- // ....
- // (if (local.get 0) (then (nop)) (else (nop)))
- // return
- // )
- // we have the continuation block (of if-block) corresponding to "return" opcode.
- labelKindContinuation
- labelKindReturn
- labelKindNum
-)
-
-// unionOperation implements Operation and is the compilation (engine.lowerIR) result of a interpreterir.Operation.
-//
-// Not all operations result in a unionOperation, e.g. interpreterir.OperationI32ReinterpretFromF32, and some operations are
-// more complex than others, e.g. interpreterir.NewOperationBrTable.
-//
-// Note: This is a form of union type as it can store fields needed for any operation. Hence, most fields are opaque and
-// only relevant when in context of its kind.
-type unionOperation struct {
- // Kind determines how to interpret the other fields in this struct.
- Kind operationKind
- B1, B2 byte
- B3 bool
- U1, U2 uint64
- U3 uint64
- Us []uint64
-}
-
-// String implements fmt.Stringer.
-func (o unionOperation) String() string {
- switch o.Kind {
- case operationKindUnreachable,
- operationKindSelect,
- operationKindMemorySize,
- operationKindMemoryGrow,
- operationKindI32WrapFromI64,
- operationKindF32DemoteFromF64,
- operationKindF64PromoteFromF32,
- operationKindI32ReinterpretFromF32,
- operationKindI64ReinterpretFromF64,
- operationKindF32ReinterpretFromI32,
- operationKindF64ReinterpretFromI64,
- operationKindSignExtend32From8,
- operationKindSignExtend32From16,
- operationKindSignExtend64From8,
- operationKindSignExtend64From16,
- operationKindSignExtend64From32,
- operationKindMemoryInit,
- operationKindDataDrop,
- operationKindMemoryCopy,
- operationKindMemoryFill,
- operationKindTableInit,
- operationKindElemDrop,
- operationKindTableCopy,
- operationKindRefFunc,
- operationKindTableGet,
- operationKindTableSet,
- operationKindTableSize,
- operationKindTableGrow,
- operationKindTableFill,
- operationKindBuiltinFunctionCheckExitCode:
- return o.Kind.String()
-
- case operationKindCall,
- operationKindGlobalGet,
- operationKindGlobalSet:
- return fmt.Sprintf("%s %d", o.Kind, o.B1)
-
- case operationKindLabel:
- return label(o.U1).String()
-
- case operationKindBr:
- return fmt.Sprintf("%s %s", o.Kind, label(o.U1).String())
-
- case operationKindBrIf:
- thenTarget := label(o.U1)
- elseTarget := label(o.U2)
- return fmt.Sprintf("%s %s, %s", o.Kind, thenTarget, elseTarget)
-
- case operationKindBrTable:
- var targets []string
- var defaultLabel label
- if len(o.Us) > 0 {
- targets = make([]string, len(o.Us)-1)
- for i, t := range o.Us[1:] {
- targets[i] = label(t).String()
- }
- defaultLabel = label(o.Us[0])
- }
- return fmt.Sprintf("%s [%s] %s", o.Kind, strings.Join(targets, ","), defaultLabel)
-
- case operationKindCallIndirect:
- return fmt.Sprintf("%s: type=%d, table=%d", o.Kind, o.U1, o.U2)
-
- case operationKindDrop:
- start := int64(o.U1)
- end := int64(o.U2)
- return fmt.Sprintf("%s %d..%d", o.Kind, start, end)
-
- case operationKindPick, operationKindSet:
- return fmt.Sprintf("%s %d (is_vector=%v)", o.Kind, o.U1, o.B3)
-
- case operationKindLoad, operationKindStore:
- return fmt.Sprintf("%s.%s (align=%d, offset=%d)", unsignedType(o.B1), o.Kind, o.U1, o.U2)
-
- case operationKindLoad8,
- operationKindLoad16:
- return fmt.Sprintf("%s.%s (align=%d, offset=%d)", signedType(o.B1), o.Kind, o.U1, o.U2)
-
- case operationKindStore8,
- operationKindStore16,
- operationKindStore32:
- return fmt.Sprintf("%s (align=%d, offset=%d)", o.Kind, o.U1, o.U2)
-
- case operationKindLoad32:
- var t string
- if o.B1 == 1 {
- t = "i64"
- } else {
- t = "u64"
- }
- return fmt.Sprintf("%s.%s (align=%d, offset=%d)", t, o.Kind, o.U1, o.U2)
-
- case operationKindEq,
- operationKindNe,
- operationKindAdd,
- operationKindSub,
- operationKindMul:
- return fmt.Sprintf("%s.%s", unsignedType(o.B1), o.Kind)
-
- case operationKindEqz,
- operationKindClz,
- operationKindCtz,
- operationKindPopcnt,
- operationKindAnd,
- operationKindOr,
- operationKindXor,
- operationKindShl,
- operationKindRotl,
- operationKindRotr:
- return fmt.Sprintf("%s.%s", unsignedInt(o.B1), o.Kind)
-
- case operationKindRem, operationKindShr:
- return fmt.Sprintf("%s.%s", signedInt(o.B1), o.Kind)
-
- case operationKindLt,
- operationKindGt,
- operationKindLe,
- operationKindGe,
- operationKindDiv:
- return fmt.Sprintf("%s.%s", signedType(o.B1), o.Kind)
-
- case operationKindAbs,
- operationKindNeg,
- operationKindCeil,
- operationKindFloor,
- operationKindTrunc,
- operationKindNearest,
- operationKindSqrt,
- operationKindMin,
- operationKindMax,
- operationKindCopysign:
- return fmt.Sprintf("%s.%s", float(o.B1), o.Kind)
-
- case operationKindConstI32,
- operationKindConstI64:
- return fmt.Sprintf("%s %#x", o.Kind, o.U1)
-
- case operationKindConstF32:
- return fmt.Sprintf("%s %f", o.Kind, math.Float32frombits(uint32(o.U1)))
- case operationKindConstF64:
- return fmt.Sprintf("%s %f", o.Kind, math.Float64frombits(o.U1))
-
- case operationKindITruncFromF:
- return fmt.Sprintf("%s.%s.%s (non_trapping=%v)", signedInt(o.B2), o.Kind, float(o.B1), o.B3)
- case operationKindFConvertFromI:
- return fmt.Sprintf("%s.%s.%s", float(o.B2), o.Kind, signedInt(o.B1))
- case operationKindExtend:
- var in, out string
- if o.B3 {
- in = "i32"
- out = "i64"
- } else {
- in = "u32"
- out = "u64"
- }
- return fmt.Sprintf("%s.%s.%s", out, o.Kind, in)
-
- case operationKindV128Const:
- return fmt.Sprintf("%s [%#x, %#x]", o.Kind, o.U1, o.U2)
- case operationKindV128Add,
- operationKindV128Sub:
- return fmt.Sprintf("%s (shape=%s)", o.Kind, shapeName(o.B1))
- case operationKindV128Load,
- operationKindV128LoadLane,
- operationKindV128Store,
- operationKindV128StoreLane,
- operationKindV128ExtractLane,
- operationKindV128ReplaceLane,
- operationKindV128Splat,
- operationKindV128Shuffle,
- operationKindV128Swizzle,
- operationKindV128AnyTrue,
- operationKindV128AllTrue,
- operationKindV128BitMask,
- operationKindV128And,
- operationKindV128Not,
- operationKindV128Or,
- operationKindV128Xor,
- operationKindV128Bitselect,
- operationKindV128AndNot,
- operationKindV128Shl,
- operationKindV128Shr,
- operationKindV128Cmp,
- operationKindV128AddSat,
- operationKindV128SubSat,
- operationKindV128Mul,
- operationKindV128Div,
- operationKindV128Neg,
- operationKindV128Sqrt,
- operationKindV128Abs,
- operationKindV128Popcnt,
- operationKindV128Min,
- operationKindV128Max,
- operationKindV128AvgrU,
- operationKindV128Pmin,
- operationKindV128Pmax,
- operationKindV128Ceil,
- operationKindV128Floor,
- operationKindV128Trunc,
- operationKindV128Nearest,
- operationKindV128Extend,
- operationKindV128ExtMul,
- operationKindV128Q15mulrSatS,
- operationKindV128ExtAddPairwise,
- operationKindV128FloatPromote,
- operationKindV128FloatDemote,
- operationKindV128FConvertFromI,
- operationKindV128Dot,
- operationKindV128Narrow:
- return o.Kind.String()
-
- case operationKindV128ITruncSatFromF:
- if o.B3 {
- return fmt.Sprintf("%s.%sS", o.Kind, shapeName(o.B1))
- } else {
- return fmt.Sprintf("%s.%sU", o.Kind, shapeName(o.B1))
- }
-
- case operationKindAtomicMemoryWait,
- operationKindAtomicMemoryNotify,
- operationKindAtomicFence,
- operationKindAtomicLoad,
- operationKindAtomicLoad8,
- operationKindAtomicLoad16,
- operationKindAtomicStore,
- operationKindAtomicStore8,
- operationKindAtomicStore16,
- operationKindAtomicRMW,
- operationKindAtomicRMW8,
- operationKindAtomicRMW16,
- operationKindAtomicRMWCmpxchg,
- operationKindAtomicRMW8Cmpxchg,
- operationKindAtomicRMW16Cmpxchg:
- return o.Kind.String()
-
- default:
- panic(fmt.Sprintf("TODO: %v", o.Kind))
- }
-}
-
-// NewOperationUnreachable is a constructor for unionOperation with operationKindUnreachable
-//
-// This corresponds to wasm.OpcodeUnreachable.
-//
-// The engines are expected to exit the execution with wasmruntime.ErrRuntimeUnreachable error.
-func newOperationUnreachable() unionOperation {
- return unionOperation{Kind: operationKindUnreachable}
-}
-
-// NewOperationLabel is a constructor for unionOperation with operationKindLabel.
-//
-// This is used to inform the engines of the beginning of a label.
-func newOperationLabel(label label) unionOperation {
- return unionOperation{Kind: operationKindLabel, U1: uint64(label)}
-}
-
-// NewOperationBr is a constructor for unionOperation with operationKindBr.
-//
-// The engines are expected to branch into U1 label.
-func newOperationBr(target label) unionOperation {
- return unionOperation{Kind: operationKindBr, U1: uint64(target)}
-}
-
-// NewOperationBrIf is a constructor for unionOperation with operationKindBrIf.
-//
-// The engines are expected to pop a value and branch into U1 label if the value equals 1.
-// Otherwise, the code branches into U2 label.
-func newOperationBrIf(thenTarget, elseTarget label, thenDrop inclusiveRange) unionOperation {
- return unionOperation{
- Kind: operationKindBrIf,
- U1: uint64(thenTarget),
- U2: uint64(elseTarget),
- U3: thenDrop.AsU64(),
- }
-}
-
-// NewOperationBrTable is a constructor for unionOperation with operationKindBrTable.
-//
-// This corresponds to wasm.OpcodeBrTableName except that the label
-// here means the interpreterir level, not the ones of Wasm.
-//
-// The engines are expected to do the br_table operation based on the default (Us[len(Us)-1], Us[len(Us)-2]) and
-// targets (Us[:len(Us)-1], Rs[:len(Us)-1]). More precisely, this pops a value from the stack (called "index")
-// and decides which branch we go into next based on the value.
-//
-// For example, assume we have operations like {default: L_DEFAULT, targets: [L0, L1, L2]}.
-// If "index" >= len(defaults), then branch into the L_DEFAULT label.
-// Otherwise, we enter label of targets[index].
-func newOperationBrTable(targetLabelsAndRanges []uint64) unionOperation {
- return unionOperation{
- Kind: operationKindBrTable,
- Us: targetLabelsAndRanges,
- }
-}
-
-// NewOperationCall is a constructor for unionOperation with operationKindCall.
-//
-// This corresponds to wasm.OpcodeCallName, and engines are expected to
-// enter into a function whose index equals OperationCall.FunctionIndex.
-func newOperationCall(functionIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindCall, U1: uint64(functionIndex)}
-}
-
-// NewOperationCallIndirect implements Operation.
-//
-// This corresponds to wasm.OpcodeCallIndirectName, and engines are expected to
-// consume the one value from the top of stack (called "offset"),
-// and make a function call against the function whose function address equals
-// Tables[OperationCallIndirect.TableIndex][offset].
-//
-// Note: This is called indirect function call in the sense that the target function is indirectly
-// determined by the current state (top value) of the stack.
-// Therefore, two checks are performed at runtime before entering the target function:
-// 1) whether "offset" exceeds the length of table Tables[OperationCallIndirect.TableIndex].
-// 2) whether the type of the function table[offset] matches the function type specified by OperationCallIndirect.TypeIndex.
-func newOperationCallIndirect(typeIndex, tableIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindCallIndirect, U1: uint64(typeIndex), U2: uint64(tableIndex)}
-}
-
-// inclusiveRange is the range which spans across the value stack starting from the top to the bottom, and
-// both boundary are included in the range.
-type inclusiveRange struct {
- Start, End int32
-}
-
-// AsU64 is be used to convert inclusiveRange to uint64 so that it can be stored in unionOperation.
-func (i inclusiveRange) AsU64() uint64 {
- return uint64(uint32(i.Start))<<32 | uint64(uint32(i.End))
-}
-
-// inclusiveRangeFromU64 retrieves inclusiveRange from the given uint64 which is stored in unionOperation.
-func inclusiveRangeFromU64(v uint64) inclusiveRange {
- return inclusiveRange{
- Start: int32(uint32(v >> 32)),
- End: int32(uint32(v)),
- }
-}
-
-// nopinclusiveRange is inclusiveRange which corresponds to no-operation.
-var nopinclusiveRange = inclusiveRange{Start: -1, End: -1}
-
-// NewOperationDrop is a constructor for unionOperation with operationKindDrop.
-//
-// The engines are expected to discard the values selected by NewOperationDrop.Depth which
-// starts from the top of the stack to the bottom.
-//
-// depth spans across the uint64 value stack at runtime to be dropped by this operation.
-func newOperationDrop(depth inclusiveRange) unionOperation {
- return unionOperation{Kind: operationKindDrop, U1: depth.AsU64()}
-}
-
-// NewOperationSelect is a constructor for unionOperation with operationKindSelect.
-//
-// This corresponds to wasm.OpcodeSelect.
-//
-// The engines are expected to pop three values, say [..., x2, x1, c], then if the value "c" equals zero,
-// "x1" is pushed back onto the stack and, otherwise "x2" is pushed back.
-//
-// isTargetVector true if the selection target value's type is wasm.ValueTypeV128.
-func newOperationSelect(isTargetVector bool) unionOperation {
- return unionOperation{Kind: operationKindSelect, B3: isTargetVector}
-}
-
-// NewOperationPick is a constructor for unionOperation with operationKindPick.
-//
-// The engines are expected to copy a value pointed by depth, and push the
-// copied value onto the top of the stack.
-//
-// depth is the location of the pick target in the uint64 value stack at runtime.
-// If isTargetVector=true, this points to the location of the lower 64-bits of the vector.
-func newOperationPick(depth int, isTargetVector bool) unionOperation {
- return unionOperation{Kind: operationKindPick, U1: uint64(depth), B3: isTargetVector}
-}
-
-// NewOperationSet is a constructor for unionOperation with operationKindSet.
-//
-// The engines are expected to set the top value of the stack to the location specified by
-// depth.
-//
-// depth is the location of the set target in the uint64 value stack at runtime.
-// If isTargetVector=true, this points the location of the lower 64-bits of the vector.
-func newOperationSet(depth int, isTargetVector bool) unionOperation {
- return unionOperation{Kind: operationKindSet, U1: uint64(depth), B3: isTargetVector}
-}
-
-// NewOperationGlobalGet is a constructor for unionOperation with operationKindGlobalGet.
-//
-// The engines are expected to read the global value specified by OperationGlobalGet.Index,
-// and push the copy of the value onto the stack.
-//
-// See wasm.OpcodeGlobalGet.
-func newOperationGlobalGet(index uint32) unionOperation {
- return unionOperation{Kind: operationKindGlobalGet, U1: uint64(index)}
-}
-
-// NewOperationGlobalSet is a constructor for unionOperation with operationKindGlobalSet.
-//
-// The engines are expected to consume the value from the top of the stack,
-// and write the value into the global specified by OperationGlobalSet.Index.
-//
-// See wasm.OpcodeGlobalSet.
-func newOperationGlobalSet(index uint32) unionOperation {
- return unionOperation{Kind: operationKindGlobalSet, U1: uint64(index)}
-}
-
-// memoryArg is the "memarg" to all memory instructions.
-//
-// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#memory-instructions%E2%91%A0
-type memoryArg struct {
- // Alignment the expected alignment (expressed as the exponent of a power of 2). Default to the natural alignment.
- //
- // "Natural alignment" is defined here as the smallest power of two that can hold the size of the value type. Ex
- // wasm.ValueTypeI64 is encoded in 8 little-endian bytes. 2^3 = 8, so the natural alignment is three.
- Alignment uint32
-
- // Offset is the address offset added to the instruction's dynamic address operand, yielding a 33-bit effective
- // address that is the zero-based index at which the memory is accessed. Default to zero.
- Offset uint32
-}
-
-// NewOperationLoad is a constructor for unionOperation with operationKindLoad.
-//
-// This corresponds to wasm.OpcodeI32LoadName wasm.OpcodeI64LoadName wasm.OpcodeF32LoadName and wasm.OpcodeF64LoadName.
-//
-// The engines are expected to check the boundary of memory length, and exit the execution if this exceeds the boundary,
-// otherwise load the corresponding value following the semantics of the corresponding WebAssembly instruction.
-func newOperationLoad(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindLoad, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationLoad8 is a constructor for unionOperation with operationKindLoad8.
-//
-// This corresponds to wasm.OpcodeI32Load8SName wasm.OpcodeI32Load8UName wasm.OpcodeI64Load8SName wasm.OpcodeI64Load8UName.
-//
-// The engines are expected to check the boundary of memory length, and exit the execution if this exceeds the boundary,
-// otherwise load the corresponding value following the semantics of the corresponding WebAssembly instruction.
-func newOperationLoad8(signedInt signedInt, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindLoad8, B1: byte(signedInt), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationLoad16 is a constructor for unionOperation with operationKindLoad16.
-//
-// This corresponds to wasm.OpcodeI32Load16SName wasm.OpcodeI32Load16UName wasm.OpcodeI64Load16SName wasm.OpcodeI64Load16UName.
-//
-// The engines are expected to check the boundary of memory length, and exit the execution if this exceeds the boundary,
-// otherwise load the corresponding value following the semantics of the corresponding WebAssembly instruction.
-func newOperationLoad16(signedInt signedInt, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindLoad16, B1: byte(signedInt), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationLoad32 is a constructor for unionOperation with operationKindLoad32.
-//
-// This corresponds to wasm.OpcodeI64Load32SName wasm.OpcodeI64Load32UName.
-//
-// The engines are expected to check the boundary of memory length, and exit the execution if this exceeds the boundary,
-// otherwise load the corresponding value following the semantics of the corresponding WebAssembly instruction.
-func newOperationLoad32(signed bool, arg memoryArg) unionOperation {
- sigB := byte(0)
- if signed {
- sigB = 1
- }
- return unionOperation{Kind: operationKindLoad32, B1: sigB, U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationStore is a constructor for unionOperation with operationKindStore.
-//
-// # This corresponds to wasm.OpcodeI32StoreName wasm.OpcodeI64StoreName wasm.OpcodeF32StoreName wasm.OpcodeF64StoreName
-//
-// The engines are expected to check the boundary of memory length, and exit the execution if this exceeds the boundary,
-// otherwise store the corresponding value following the semantics of the corresponding WebAssembly instruction.
-func newOperationStore(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindStore, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationStore8 is a constructor for unionOperation with operationKindStore8.
-//
-// # This corresponds to wasm.OpcodeI32Store8Name wasm.OpcodeI64Store8Name
-//
-// The engines are expected to check the boundary of memory length, and exit the execution if this exceeds the boundary,
-// otherwise store the corresponding value following the semantics of the corresponding WebAssembly instruction.
-func newOperationStore8(arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindStore8, U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationStore16 is a constructor for unionOperation with operationKindStore16.
-//
-// # This corresponds to wasm.OpcodeI32Store16Name wasm.OpcodeI64Store16Name
-//
-// The engines are expected to check the boundary of memory length, and exit the execution if this exceeds the boundary,
-// otherwise store the corresponding value following the semantics of the corresponding WebAssembly instruction.
-func newOperationStore16(arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindStore16, U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationStore32 is a constructor for unionOperation with operationKindStore32.
-//
-// # This corresponds to wasm.OpcodeI64Store32Name
-//
-// The engines are expected to check the boundary of memory length, and exit the execution if this exceeds the boundary,
-// otherwise store the corresponding value following the semantics of the corresponding WebAssembly instruction.
-func newOperationStore32(arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindStore32, U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationMemorySize is a constructor for unionOperation with operationKindMemorySize.
-//
-// This corresponds to wasm.OpcodeMemorySize.
-//
-// The engines are expected to push the current page size of the memory onto the stack.
-func newOperationMemorySize() unionOperation {
- return unionOperation{Kind: operationKindMemorySize}
-}
-
-// NewOperationMemoryGrow is a constructor for unionOperation with operationKindMemoryGrow.
-//
-// This corresponds to wasm.OpcodeMemoryGrow.
-//
-// The engines are expected to pop one value from the top of the stack, then
-// execute wasm.MemoryInstance Grow with the value, and push the previous
-// page size of the memory onto the stack.
-func newOperationMemoryGrow() unionOperation {
- return unionOperation{Kind: operationKindMemoryGrow}
-}
-
-// NewOperationConstI32 is a constructor for unionOperation with OperationConstI32.
-//
-// This corresponds to wasm.OpcodeI32Const.
-func newOperationConstI32(value uint32) unionOperation {
- return unionOperation{Kind: operationKindConstI32, U1: uint64(value)}
-}
-
-// NewOperationConstI64 is a constructor for unionOperation with OperationConstI64.
-//
-// This corresponds to wasm.OpcodeI64Const.
-func newOperationConstI64(value uint64) unionOperation {
- return unionOperation{Kind: operationKindConstI64, U1: value}
-}
-
-// NewOperationConstF32 is a constructor for unionOperation with OperationConstF32.
-//
-// This corresponds to wasm.OpcodeF32Const.
-func newOperationConstF32(value float32) unionOperation {
- return unionOperation{Kind: operationKindConstF32, U1: uint64(math.Float32bits(value))}
-}
-
-// NewOperationConstF64 is a constructor for unionOperation with OperationConstF64.
-//
-// This corresponds to wasm.OpcodeF64Const.
-func newOperationConstF64(value float64) unionOperation {
- return unionOperation{Kind: operationKindConstF64, U1: math.Float64bits(value)}
-}
-
-// NewOperationEq is a constructor for unionOperation with operationKindEq.
-//
-// This corresponds to wasm.OpcodeI32EqName wasm.OpcodeI64EqName wasm.OpcodeF32EqName wasm.OpcodeF64EqName
-func newOperationEq(b unsignedType) unionOperation {
- return unionOperation{Kind: operationKindEq, B1: byte(b)}
-}
-
-// NewOperationNe is a constructor for unionOperation with operationKindNe.
-//
-// This corresponds to wasm.OpcodeI32NeName wasm.OpcodeI64NeName wasm.OpcodeF32NeName wasm.OpcodeF64NeName
-func newOperationNe(b unsignedType) unionOperation {
- return unionOperation{Kind: operationKindNe, B1: byte(b)}
-}
-
-// NewOperationEqz is a constructor for unionOperation with operationKindEqz.
-//
-// This corresponds to wasm.OpcodeI32EqzName wasm.OpcodeI64EqzName
-func newOperationEqz(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindEqz, B1: byte(b)}
-}
-
-// NewOperationLt is a constructor for unionOperation with operationKindLt.
-//
-// This corresponds to wasm.OpcodeI32LtS wasm.OpcodeI32LtU wasm.OpcodeI64LtS wasm.OpcodeI64LtU wasm.OpcodeF32Lt wasm.OpcodeF64Lt
-func newOperationLt(b signedType) unionOperation {
- return unionOperation{Kind: operationKindLt, B1: byte(b)}
-}
-
-// NewOperationGt is a constructor for unionOperation with operationKindGt.
-//
-// This corresponds to wasm.OpcodeI32GtS wasm.OpcodeI32GtU wasm.OpcodeI64GtS wasm.OpcodeI64GtU wasm.OpcodeF32Gt wasm.OpcodeF64Gt
-func newOperationGt(b signedType) unionOperation {
- return unionOperation{Kind: operationKindGt, B1: byte(b)}
-}
-
-// NewOperationLe is a constructor for unionOperation with operationKindLe.
-//
-// This corresponds to wasm.OpcodeI32LeS wasm.OpcodeI32LeU wasm.OpcodeI64LeS wasm.OpcodeI64LeU wasm.OpcodeF32Le wasm.OpcodeF64Le
-func newOperationLe(b signedType) unionOperation {
- return unionOperation{Kind: operationKindLe, B1: byte(b)}
-}
-
-// NewOperationGe is a constructor for unionOperation with operationKindGe.
-//
-// This corresponds to wasm.OpcodeI32GeS wasm.OpcodeI32GeU wasm.OpcodeI64GeS wasm.OpcodeI64GeU wasm.OpcodeF32Ge wasm.OpcodeF64Ge
-// NewOperationGe is the constructor for OperationGe
-func newOperationGe(b signedType) unionOperation {
- return unionOperation{Kind: operationKindGe, B1: byte(b)}
-}
-
-// NewOperationAdd is a constructor for unionOperation with operationKindAdd.
-//
-// This corresponds to wasm.OpcodeI32AddName wasm.OpcodeI64AddName wasm.OpcodeF32AddName wasm.OpcodeF64AddName.
-func newOperationAdd(b unsignedType) unionOperation {
- return unionOperation{Kind: operationKindAdd, B1: byte(b)}
-}
-
-// NewOperationSub is a constructor for unionOperation with operationKindSub.
-//
-// This corresponds to wasm.OpcodeI32SubName wasm.OpcodeI64SubName wasm.OpcodeF32SubName wasm.OpcodeF64SubName.
-func newOperationSub(b unsignedType) unionOperation {
- return unionOperation{Kind: operationKindSub, B1: byte(b)}
-}
-
-// NewOperationMul is a constructor for unionOperation with wperationKindMul.
-//
-// This corresponds to wasm.OpcodeI32MulName wasm.OpcodeI64MulName wasm.OpcodeF32MulName wasm.OpcodeF64MulName.
-// NewOperationMul is the constructor for OperationMul
-func newOperationMul(b unsignedType) unionOperation {
- return unionOperation{Kind: operationKindMul, B1: byte(b)}
-}
-
-// NewOperationClz is a constructor for unionOperation with operationKindClz.
-//
-// This corresponds to wasm.OpcodeI32ClzName wasm.OpcodeI64ClzName.
-//
-// The engines are expected to count up the leading zeros in the
-// current top of the stack, and push the count result.
-// For example, stack of [..., 0x00_ff_ff_ff] results in [..., 8].
-// See wasm.OpcodeI32Clz wasm.OpcodeI64Clz
-func newOperationClz(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindClz, B1: byte(b)}
-}
-
-// NewOperationCtz is a constructor for unionOperation with operationKindCtz.
-//
-// This corresponds to wasm.OpcodeI32CtzName wasm.OpcodeI64CtzName.
-//
-// The engines are expected to count up the trailing zeros in the
-// current top of the stack, and push the count result.
-// For example, stack of [..., 0xff_ff_ff_00] results in [..., 8].
-func newOperationCtz(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindCtz, B1: byte(b)}
-}
-
-// NewOperationPopcnt is a constructor for unionOperation with operationKindPopcnt.
-//
-// This corresponds to wasm.OpcodeI32PopcntName wasm.OpcodeI64PopcntName.
-//
-// The engines are expected to count up the number of set bits in the
-// current top of the stack, and push the count result.
-// For example, stack of [..., 0b00_00_00_11] results in [..., 2].
-func newOperationPopcnt(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindPopcnt, B1: byte(b)}
-}
-
-// NewOperationDiv is a constructor for unionOperation with operationKindDiv.
-//
-// This corresponds to wasm.OpcodeI32DivS wasm.OpcodeI32DivU wasm.OpcodeI64DivS
-//
-// wasm.OpcodeI64DivU wasm.OpcodeF32Div wasm.OpcodeF64Div.
-func newOperationDiv(b signedType) unionOperation {
- return unionOperation{Kind: operationKindDiv, B1: byte(b)}
-}
-
-// NewOperationRem is a constructor for unionOperation with operationKindRem.
-//
-// This corresponds to wasm.OpcodeI32RemS wasm.OpcodeI32RemU wasm.OpcodeI64RemS wasm.OpcodeI64RemU.
-//
-// The engines are expected to perform division on the top
-// two values of integer type on the stack and puts the remainder of the result
-// onto the stack. For example, stack [..., 10, 3] results in [..., 1] where
-// the quotient is discarded.
-// NewOperationRem is the constructor for OperationRem
-func newOperationRem(b signedInt) unionOperation {
- return unionOperation{Kind: operationKindRem, B1: byte(b)}
-}
-
-// NewOperationAnd is a constructor for unionOperation with operationKindAnd.
-//
-// # This corresponds to wasm.OpcodeI32AndName wasm.OpcodeI64AndName
-//
-// The engines are expected to perform "And" operation on
-// top two values on the stack, and pushes the result.
-func newOperationAnd(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindAnd, B1: byte(b)}
-}
-
-// NewOperationOr is a constructor for unionOperation with operationKindOr.
-//
-// # This corresponds to wasm.OpcodeI32OrName wasm.OpcodeI64OrName
-//
-// The engines are expected to perform "Or" operation on
-// top two values on the stack, and pushes the result.
-func newOperationOr(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindOr, B1: byte(b)}
-}
-
-// NewOperationXor is a constructor for unionOperation with operationKindXor.
-//
-// # This corresponds to wasm.OpcodeI32XorName wasm.OpcodeI64XorName
-//
-// The engines are expected to perform "Xor" operation on
-// top two values on the stack, and pushes the result.
-func newOperationXor(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindXor, B1: byte(b)}
-}
-
-// NewOperationShl is a constructor for unionOperation with operationKindShl.
-//
-// # This corresponds to wasm.OpcodeI32ShlName wasm.OpcodeI64ShlName
-//
-// The engines are expected to perform "Shl" operation on
-// top two values on the stack, and pushes the result.
-func newOperationShl(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindShl, B1: byte(b)}
-}
-
-// NewOperationShr is a constructor for unionOperation with operationKindShr.
-//
-// # This corresponds to wasm.OpcodeI32ShrSName wasm.OpcodeI32ShrUName wasm.OpcodeI64ShrSName wasm.OpcodeI64ShrUName
-//
-// If OperationShr.Type is signed integer, then, the engines are expected to perform arithmetic right shift on the two
-// top values on the stack, otherwise do the logical right shift.
-func newOperationShr(b signedInt) unionOperation {
- return unionOperation{Kind: operationKindShr, B1: byte(b)}
-}
-
-// NewOperationRotl is a constructor for unionOperation with operationKindRotl.
-//
-// # This corresponds to wasm.OpcodeI32RotlName wasm.OpcodeI64RotlName
-//
-// The engines are expected to perform "Rotl" operation on
-// top two values on the stack, and pushes the result.
-func newOperationRotl(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindRotl, B1: byte(b)}
-}
-
-// NewOperationRotr is a constructor for unionOperation with operationKindRotr.
-//
-// # This corresponds to wasm.OpcodeI32RotrName wasm.OpcodeI64RotrName
-//
-// The engines are expected to perform "Rotr" operation on
-// top two values on the stack, and pushes the result.
-func newOperationRotr(b unsignedInt) unionOperation {
- return unionOperation{Kind: operationKindRotr, B1: byte(b)}
-}
-
-// NewOperationAbs is a constructor for unionOperation with operationKindAbs.
-//
-// This corresponds to wasm.OpcodeF32Abs wasm.OpcodeF64Abs
-func newOperationAbs(b float) unionOperation {
- return unionOperation{Kind: operationKindAbs, B1: byte(b)}
-}
-
-// NewOperationNeg is a constructor for unionOperation with operationKindNeg.
-//
-// This corresponds to wasm.OpcodeF32Neg wasm.OpcodeF64Neg
-func newOperationNeg(b float) unionOperation {
- return unionOperation{Kind: operationKindNeg, B1: byte(b)}
-}
-
-// NewOperationCeil is a constructor for unionOperation with operationKindCeil.
-//
-// This corresponds to wasm.OpcodeF32CeilName wasm.OpcodeF64CeilName
-func newOperationCeil(b float) unionOperation {
- return unionOperation{Kind: operationKindCeil, B1: byte(b)}
-}
-
-// NewOperationFloor is a constructor for unionOperation with operationKindFloor.
-//
-// This corresponds to wasm.OpcodeF32FloorName wasm.OpcodeF64FloorName
-func newOperationFloor(b float) unionOperation {
- return unionOperation{Kind: operationKindFloor, B1: byte(b)}
-}
-
-// NewOperationTrunc is a constructor for unionOperation with operationKindTrunc.
-//
-// This corresponds to wasm.OpcodeF32TruncName wasm.OpcodeF64TruncName
-func newOperationTrunc(b float) unionOperation {
- return unionOperation{Kind: operationKindTrunc, B1: byte(b)}
-}
-
-// NewOperationNearest is a constructor for unionOperation with operationKindNearest.
-//
-// # This corresponds to wasm.OpcodeF32NearestName wasm.OpcodeF64NearestName
-//
-// Note: this is *not* equivalent to math.Round and instead has the same
-// the semantics of LLVM's rint intrinsic. See https://llvm.org/docs/LangRef.html#llvm-rint-intrinsic.
-// For example, math.Round(-4.5) produces -5 while we want to produce -4.
-func newOperationNearest(b float) unionOperation {
- return unionOperation{Kind: operationKindNearest, B1: byte(b)}
-}
-
-// NewOperationSqrt is a constructor for unionOperation with operationKindSqrt.
-//
-// This corresponds to wasm.OpcodeF32SqrtName wasm.OpcodeF64SqrtName
-func newOperationSqrt(b float) unionOperation {
- return unionOperation{Kind: operationKindSqrt, B1: byte(b)}
-}
-
-// NewOperationMin is a constructor for unionOperation with operationKindMin.
-//
-// # This corresponds to wasm.OpcodeF32MinName wasm.OpcodeF64MinName
-//
-// The engines are expected to pop two values from the stack, and push back the maximum of
-// these two values onto the stack. For example, stack [..., 100.1, 1.9] results in [..., 1.9].
-//
-// Note: WebAssembly specifies that min/max must always return NaN if one of values is NaN,
-// which is a different behavior different from math.Min.
-func newOperationMin(b float) unionOperation {
- return unionOperation{Kind: operationKindMin, B1: byte(b)}
-}
-
-// NewOperationMax is a constructor for unionOperation with operationKindMax.
-//
-// # This corresponds to wasm.OpcodeF32MaxName wasm.OpcodeF64MaxName
-//
-// The engines are expected to pop two values from the stack, and push back the maximum of
-// these two values onto the stack. For example, stack [..., 100.1, 1.9] results in [..., 100.1].
-//
-// Note: WebAssembly specifies that min/max must always return NaN if one of values is NaN,
-// which is a different behavior different from math.Max.
-func newOperationMax(b float) unionOperation {
- return unionOperation{Kind: operationKindMax, B1: byte(b)}
-}
-
-// NewOperationCopysign is a constructor for unionOperation with operationKindCopysign.
-//
-// # This corresponds to wasm.OpcodeF32CopysignName wasm.OpcodeF64CopysignName
-//
-// The engines are expected to pop two float values from the stack, and copy the signbit of
-// the first-popped value to the last one.
-// For example, stack [..., 1.213, -5.0] results in [..., -1.213].
-func newOperationCopysign(b float) unionOperation {
- return unionOperation{Kind: operationKindCopysign, B1: byte(b)}
-}
-
-// NewOperationI32WrapFromI64 is a constructor for unionOperation with operationKindI32WrapFromI64.
-//
-// This corresponds to wasm.OpcodeI32WrapI64 and equivalent to uint64(uint32(v)) in Go.
-//
-// The engines are expected to replace the 64-bit int on top of the stack
-// with the corresponding 32-bit integer.
-func newOperationI32WrapFromI64() unionOperation {
- return unionOperation{Kind: operationKindI32WrapFromI64}
-}
-
-// NewOperationITruncFromF is a constructor for unionOperation with operationKindITruncFromF.
-//
-// This corresponds to
-//
-// wasm.OpcodeI32TruncF32SName wasm.OpcodeI32TruncF32UName wasm.OpcodeI32TruncF64SName
-// wasm.OpcodeI32TruncF64UName wasm.OpcodeI64TruncF32SName wasm.OpcodeI64TruncF32UName wasm.OpcodeI64TruncF64SName
-// wasm.OpcodeI64TruncF64UName. wasm.OpcodeI32TruncSatF32SName wasm.OpcodeI32TruncSatF32UName
-// wasm.OpcodeI32TruncSatF64SName wasm.OpcodeI32TruncSatF64UName wasm.OpcodeI64TruncSatF32SName
-// wasm.OpcodeI64TruncSatF32UName wasm.OpcodeI64TruncSatF64SName wasm.OpcodeI64TruncSatF64UName
-//
-// See [1] and [2] for when we encounter undefined behavior in the WebAssembly specification if NewOperationITruncFromF.NonTrapping == false.
-// To summarize, if the source float value is NaN or doesn't fit in the destination range of integers (incl. +=Inf),
-// then the runtime behavior is undefined. In wazero, the engines are expected to exit the execution in these undefined cases with
-// wasmruntime.ErrRuntimeInvalidConversionToInteger error.
-//
-// [1] https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#-hrefop-trunc-umathrmtruncmathsfu_m-n-z for unsigned integers.
-// [2] https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#-hrefop-trunc-smathrmtruncmathsfs_m-n-z for signed integers.
-//
-// nonTrapping true if this conversion is "nontrapping" in the sense of the
-// https://github.com/WebAssembly/spec/blob/ce4b6c4d47eb06098cc7ab2e81f24748da822f20/proposals/nontrapping-float-to-int-conversion/Overview.md
-func newOperationITruncFromF(inputType float, outputType signedInt, nonTrapping bool) unionOperation {
- return unionOperation{
- Kind: operationKindITruncFromF,
- B1: byte(inputType),
- B2: byte(outputType),
- B3: nonTrapping,
- }
-}
-
-// NewOperationFConvertFromI is a constructor for unionOperation with operationKindFConvertFromI.
-//
-// This corresponds to
-//
-// wasm.OpcodeF32ConvertI32SName wasm.OpcodeF32ConvertI32UName wasm.OpcodeF32ConvertI64SName wasm.OpcodeF32ConvertI64UName
-// wasm.OpcodeF64ConvertI32SName wasm.OpcodeF64ConvertI32UName wasm.OpcodeF64ConvertI64SName wasm.OpcodeF64ConvertI64UName
-//
-// and equivalent to float32(uint32(x)), float32(int32(x)), etc in Go.
-func newOperationFConvertFromI(inputType signedInt, outputType float) unionOperation {
- return unionOperation{
- Kind: operationKindFConvertFromI,
- B1: byte(inputType),
- B2: byte(outputType),
- }
-}
-
-// NewOperationF32DemoteFromF64 is a constructor for unionOperation with operationKindF32DemoteFromF64.
-//
-// This corresponds to wasm.OpcodeF32DemoteF64 and is equivalent float32(float64(v)).
-func newOperationF32DemoteFromF64() unionOperation {
- return unionOperation{Kind: operationKindF32DemoteFromF64}
-}
-
-// NewOperationF64PromoteFromF32 is a constructor for unionOperation with operationKindF64PromoteFromF32.
-//
-// This corresponds to wasm.OpcodeF64PromoteF32 and is equivalent float64(float32(v)).
-func newOperationF64PromoteFromF32() unionOperation {
- return unionOperation{Kind: operationKindF64PromoteFromF32}
-}
-
-// NewOperationI32ReinterpretFromF32 is a constructor for unionOperation with operationKindI32ReinterpretFromF32.
-//
-// This corresponds to wasm.OpcodeI32ReinterpretF32Name.
-func newOperationI32ReinterpretFromF32() unionOperation {
- return unionOperation{Kind: operationKindI32ReinterpretFromF32}
-}
-
-// NewOperationI64ReinterpretFromF64 is a constructor for unionOperation with operationKindI64ReinterpretFromF64.
-//
-// This corresponds to wasm.OpcodeI64ReinterpretF64Name.
-func newOperationI64ReinterpretFromF64() unionOperation {
- return unionOperation{Kind: operationKindI64ReinterpretFromF64}
-}
-
-// NewOperationF32ReinterpretFromI32 is a constructor for unionOperation with operationKindF32ReinterpretFromI32.
-//
-// This corresponds to wasm.OpcodeF32ReinterpretI32Name.
-func newOperationF32ReinterpretFromI32() unionOperation {
- return unionOperation{Kind: operationKindF32ReinterpretFromI32}
-}
-
-// NewOperationF64ReinterpretFromI64 is a constructor for unionOperation with operationKindF64ReinterpretFromI64.
-//
-// This corresponds to wasm.OpcodeF64ReinterpretI64Name.
-func newOperationF64ReinterpretFromI64() unionOperation {
- return unionOperation{Kind: operationKindF64ReinterpretFromI64}
-}
-
-// NewOperationExtend is a constructor for unionOperation with operationKindExtend.
-//
-// # This corresponds to wasm.OpcodeI64ExtendI32SName wasm.OpcodeI64ExtendI32UName
-//
-// The engines are expected to extend the 32-bit signed or unsigned int on top of the stack
-// as a 64-bit integer of corresponding signedness. For unsigned case, this is just reinterpreting the
-// underlying bit pattern as 64-bit integer. For signed case, this is sign-extension which preserves the
-// original integer's sign.
-func newOperationExtend(signed bool) unionOperation {
- op := unionOperation{Kind: operationKindExtend}
- if signed {
- op.B1 = 1
- }
- return op
-}
-
-// NewOperationSignExtend32From8 is a constructor for unionOperation with operationKindSignExtend32From8.
-//
-// This corresponds to wasm.OpcodeI32Extend8SName.
-//
-// The engines are expected to sign-extend the first 8-bits of 32-bit in as signed 32-bit int.
-func newOperationSignExtend32From8() unionOperation {
- return unionOperation{Kind: operationKindSignExtend32From8}
-}
-
-// NewOperationSignExtend32From16 is a constructor for unionOperation with operationKindSignExtend32From16.
-//
-// This corresponds to wasm.OpcodeI32Extend16SName.
-//
-// The engines are expected to sign-extend the first 16-bits of 32-bit in as signed 32-bit int.
-func newOperationSignExtend32From16() unionOperation {
- return unionOperation{Kind: operationKindSignExtend32From16}
-}
-
-// NewOperationSignExtend64From8 is a constructor for unionOperation with operationKindSignExtend64From8.
-//
-// This corresponds to wasm.OpcodeI64Extend8SName.
-//
-// The engines are expected to sign-extend the first 8-bits of 64-bit in as signed 32-bit int.
-func newOperationSignExtend64From8() unionOperation {
- return unionOperation{Kind: operationKindSignExtend64From8}
-}
-
-// NewOperationSignExtend64From16 is a constructor for unionOperation with operationKindSignExtend64From16.
-//
-// This corresponds to wasm.OpcodeI64Extend16SName.
-//
-// The engines are expected to sign-extend the first 16-bits of 64-bit in as signed 32-bit int.
-func newOperationSignExtend64From16() unionOperation {
- return unionOperation{Kind: operationKindSignExtend64From16}
-}
-
-// NewOperationSignExtend64From32 is a constructor for unionOperation with operationKindSignExtend64From32.
-//
-// This corresponds to wasm.OpcodeI64Extend32SName.
-//
-// The engines are expected to sign-extend the first 32-bits of 64-bit in as signed 32-bit int.
-func newOperationSignExtend64From32() unionOperation {
- return unionOperation{Kind: operationKindSignExtend64From32}
-}
-
-// NewOperationMemoryInit is a constructor for unionOperation with operationKindMemoryInit.
-//
-// This corresponds to wasm.OpcodeMemoryInitName.
-//
-// dataIndex is the index of the data instance in ModuleInstance.DataInstances
-// by which this operation instantiates a part of the memory.
-func newOperationMemoryInit(dataIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindMemoryInit, U1: uint64(dataIndex)}
-}
-
-// NewOperationDataDrop implements Operation.
-//
-// This corresponds to wasm.OpcodeDataDropName.
-//
-// dataIndex is the index of the data instance in ModuleInstance.DataInstances
-// which this operation drops.
-func newOperationDataDrop(dataIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindDataDrop, U1: uint64(dataIndex)}
-}
-
-// NewOperationMemoryCopy is a consuctor for unionOperation with operationKindMemoryCopy.
-//
-// This corresponds to wasm.OpcodeMemoryCopyName.
-func newOperationMemoryCopy() unionOperation {
- return unionOperation{Kind: operationKindMemoryCopy}
-}
-
-// NewOperationMemoryFill is a consuctor for unionOperation with operationKindMemoryFill.
-func newOperationMemoryFill() unionOperation {
- return unionOperation{Kind: operationKindMemoryFill}
-}
-
-// NewOperationTableInit is a constructor for unionOperation with operationKindTableInit.
-//
-// This corresponds to wasm.OpcodeTableInitName.
-//
-// elemIndex is the index of the element by which this operation initializes a part of the table.
-// tableIndex is the index of the table on which this operation initialize by the target element.
-func newOperationTableInit(elemIndex, tableIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindTableInit, U1: uint64(elemIndex), U2: uint64(tableIndex)}
-}
-
-// NewOperationElemDrop is a constructor for unionOperation with operationKindElemDrop.
-//
-// This corresponds to wasm.OpcodeElemDropName.
-//
-// elemIndex is the index of the element which this operation drops.
-func newOperationElemDrop(elemIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindElemDrop, U1: uint64(elemIndex)}
-}
-
-// NewOperationTableCopy implements Operation.
-//
-// This corresponds to wasm.OpcodeTableCopyName.
-func newOperationTableCopy(srcTableIndex, dstTableIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindTableCopy, U1: uint64(srcTableIndex), U2: uint64(dstTableIndex)}
-}
-
-// NewOperationRefFunc constructor for unionOperation with operationKindRefFunc.
-//
-// This corresponds to wasm.OpcodeRefFuncName, and engines are expected to
-// push the opaque pointer value of engine specific func for the given FunctionIndex.
-//
-// Note: in wazero, we express any reference types (funcref or externref) as opaque pointers which is uint64.
-// Therefore, the engine implementations emit instructions to push the address of *function onto the stack.
-func newOperationRefFunc(functionIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindRefFunc, U1: uint64(functionIndex)}
-}
-
-// NewOperationTableGet constructor for unionOperation with operationKindTableGet.
-//
-// This corresponds to wasm.OpcodeTableGetName.
-func newOperationTableGet(tableIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindTableGet, U1: uint64(tableIndex)}
-}
-
-// NewOperationTableSet constructor for unionOperation with operationKindTableSet.
-//
-// This corresponds to wasm.OpcodeTableSetName.
-func newOperationTableSet(tableIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindTableSet, U1: uint64(tableIndex)}
-}
-
-// NewOperationTableSize constructor for unionOperation with operationKindTableSize.
-//
-// This corresponds to wasm.OpcodeTableSizeName.
-func newOperationTableSize(tableIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindTableSize, U1: uint64(tableIndex)}
-}
-
-// NewOperationTableGrow constructor for unionOperation with operationKindTableGrow.
-//
-// This corresponds to wasm.OpcodeTableGrowName.
-func newOperationTableGrow(tableIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindTableGrow, U1: uint64(tableIndex)}
-}
-
-// NewOperationTableFill constructor for unionOperation with operationKindTableFill.
-//
-// This corresponds to wasm.OpcodeTableFillName.
-func newOperationTableFill(tableIndex uint32) unionOperation {
- return unionOperation{Kind: operationKindTableFill, U1: uint64(tableIndex)}
-}
-
-// NewOperationV128Const constructor for unionOperation with operationKindV128Const
-func newOperationV128Const(lo, hi uint64) unionOperation {
- return unionOperation{Kind: operationKindV128Const, U1: lo, U2: hi}
-}
-
-// shape corresponds to a shape of v128 values.
-// https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-shape
-type shape = byte
-
-const (
- shapeI8x16 shape = iota
- shapeI16x8
- shapeI32x4
- shapeI64x2
- shapeF32x4
- shapeF64x2
-)
-
-func shapeName(s shape) (ret string) {
- switch s {
- case shapeI8x16:
- ret = "I8x16"
- case shapeI16x8:
- ret = "I16x8"
- case shapeI32x4:
- ret = "I32x4"
- case shapeI64x2:
- ret = "I64x2"
- case shapeF32x4:
- ret = "F32x4"
- case shapeF64x2:
- ret = "F64x2"
- }
- return
-}
-
-// NewOperationV128Add constructor for unionOperation with operationKindV128Add.
-//
-// This corresponds to wasm.OpcodeVecI8x16AddName wasm.OpcodeVecI16x8AddName wasm.OpcodeVecI32x4AddName
-//
-// wasm.OpcodeVecI64x2AddName wasm.OpcodeVecF32x4AddName wasm.OpcodeVecF64x2AddName
-func newOperationV128Add(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Add, B1: shape}
-}
-
-// NewOperationV128Sub constructor for unionOperation with operationKindV128Sub.
-//
-// This corresponds to wasm.OpcodeVecI8x16SubName wasm.OpcodeVecI16x8SubName wasm.OpcodeVecI32x4SubName
-//
-// wasm.OpcodeVecI64x2SubName wasm.OpcodeVecF32x4SubName wasm.OpcodeVecF64x2SubName
-func newOperationV128Sub(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Sub, B1: shape}
-}
-
-// v128LoadType represents a type of wasm.OpcodeVecV128Load* instructions.
-type v128LoadType = byte
-
-const (
- // v128LoadType128 corresponds to wasm.OpcodeVecV128LoadName.
- v128LoadType128 v128LoadType = iota
- // v128LoadType8x8s corresponds to wasm.OpcodeVecV128Load8x8SName.
- v128LoadType8x8s
- // v128LoadType8x8u corresponds to wasm.OpcodeVecV128Load8x8UName.
- v128LoadType8x8u
- // v128LoadType16x4s corresponds to wasm.OpcodeVecV128Load16x4SName
- v128LoadType16x4s
- // v128LoadType16x4u corresponds to wasm.OpcodeVecV128Load16x4UName
- v128LoadType16x4u
- // v128LoadType32x2s corresponds to wasm.OpcodeVecV128Load32x2SName
- v128LoadType32x2s
- // v128LoadType32x2u corresponds to wasm.OpcodeVecV128Load32x2UName
- v128LoadType32x2u
- // v128LoadType8Splat corresponds to wasm.OpcodeVecV128Load8SplatName
- v128LoadType8Splat
- // v128LoadType16Splat corresponds to wasm.OpcodeVecV128Load16SplatName
- v128LoadType16Splat
- // v128LoadType32Splat corresponds to wasm.OpcodeVecV128Load32SplatName
- v128LoadType32Splat
- // v128LoadType64Splat corresponds to wasm.OpcodeVecV128Load64SplatName
- v128LoadType64Splat
- // v128LoadType32zero corresponds to wasm.OpcodeVecV128Load32zeroName
- v128LoadType32zero
- // v128LoadType64zero corresponds to wasm.OpcodeVecV128Load64zeroName
- v128LoadType64zero
-)
-
-// NewOperationV128Load is a constructor for unionOperation with operationKindV128Load.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecV128LoadName wasm.OpcodeVecV128Load8x8SName wasm.OpcodeVecV128Load8x8UName
-// wasm.OpcodeVecV128Load16x4SName wasm.OpcodeVecV128Load16x4UName wasm.OpcodeVecV128Load32x2SName
-// wasm.OpcodeVecV128Load32x2UName wasm.OpcodeVecV128Load8SplatName wasm.OpcodeVecV128Load16SplatName
-// wasm.OpcodeVecV128Load32SplatName wasm.OpcodeVecV128Load64SplatName wasm.OpcodeVecV128Load32zeroName
-// wasm.OpcodeVecV128Load64zeroName
-func newOperationV128Load(loadType v128LoadType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindV128Load, B1: loadType, U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationV128LoadLane is a constructor for unionOperation with operationKindV128LoadLane.
-//
-// This corresponds to wasm.OpcodeVecV128Load8LaneName wasm.OpcodeVecV128Load16LaneName
-//
-// wasm.OpcodeVecV128Load32LaneName wasm.OpcodeVecV128Load64LaneName.
-//
-// laneIndex is >=0 && <(128/LaneSize).
-// laneSize is either 8, 16, 32, or 64.
-func newOperationV128LoadLane(laneIndex, laneSize byte, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindV128LoadLane, B1: laneSize, B2: laneIndex, U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationV128Store is a constructor for unionOperation with operationKindV128Store.
-//
-// This corresponds to wasm.OpcodeVecV128Load8LaneName wasm.OpcodeVecV128Load16LaneName
-//
-// wasm.OpcodeVecV128Load32LaneName wasm.OpcodeVecV128Load64LaneName.
-func newOperationV128Store(arg memoryArg) unionOperation {
- return unionOperation{
- Kind: operationKindV128Store,
- U1: uint64(arg.Alignment),
- U2: uint64(arg.Offset),
- }
-}
-
-// NewOperationV128StoreLane implements Operation.
-//
-// This corresponds to wasm.OpcodeVecV128Load8LaneName wasm.OpcodeVecV128Load16LaneName
-//
-// wasm.OpcodeVecV128Load32LaneName wasm.OpcodeVecV128Load64LaneName.
-//
-// laneIndex is >=0 && <(128/LaneSize).
-// laneSize is either 8, 16, 32, or 64.
-func newOperationV128StoreLane(laneIndex byte, laneSize byte, arg memoryArg) unionOperation {
- return unionOperation{
- Kind: operationKindV128StoreLane,
- B1: laneSize,
- B2: laneIndex,
- U1: uint64(arg.Alignment),
- U2: uint64(arg.Offset),
- }
-}
-
-// NewOperationV128ExtractLane is a constructor for unionOperation with operationKindV128ExtractLane.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16ExtractLaneSName wasm.OpcodeVecI8x16ExtractLaneUName
-// wasm.OpcodeVecI16x8ExtractLaneSName wasm.OpcodeVecI16x8ExtractLaneUName
-// wasm.OpcodeVecI32x4ExtractLaneName wasm.OpcodeVecI64x2ExtractLaneName
-// wasm.OpcodeVecF32x4ExtractLaneName wasm.OpcodeVecF64x2ExtractLaneName.
-//
-// laneIndex is >=0 && <M where shape = NxM.
-// signed is used when shape is either i8x16 or i16x2 to specify whether to sign-extend or not.
-func newOperationV128ExtractLane(laneIndex byte, signed bool, shape shape) unionOperation {
- return unionOperation{
- Kind: operationKindV128ExtractLane,
- B1: shape,
- B2: laneIndex,
- B3: signed,
- }
-}
-
-// NewOperationV128ReplaceLane is a constructor for unionOperation with operationKindV128ReplaceLane.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16ReplaceLaneName wasm.OpcodeVecI16x8ReplaceLaneName
-// wasm.OpcodeVecI32x4ReplaceLaneName wasm.OpcodeVecI64x2ReplaceLaneName
-// wasm.OpcodeVecF32x4ReplaceLaneName wasm.OpcodeVecF64x2ReplaceLaneName.
-//
-// laneIndex is >=0 && <M where shape = NxM.
-func newOperationV128ReplaceLane(laneIndex byte, shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128ReplaceLane, B1: shape, B2: laneIndex}
-}
-
-// NewOperationV128Splat is a constructor for unionOperation with operationKindV128Splat.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16SplatName wasm.OpcodeVecI16x8SplatName
-// wasm.OpcodeVecI32x4SplatName wasm.OpcodeVecI64x2SplatName
-// wasm.OpcodeVecF32x4SplatName wasm.OpcodeVecF64x2SplatName.
-func newOperationV128Splat(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Splat, B1: shape}
-}
-
-// NewOperationV128Shuffle is a constructor for unionOperation with operationKindV128Shuffle.
-func newOperationV128Shuffle(lanes []uint64) unionOperation {
- return unionOperation{Kind: operationKindV128Shuffle, Us: lanes}
-}
-
-// NewOperationV128Swizzle is a constructor for unionOperation with operationKindV128Swizzle.
-//
-// This corresponds to wasm.OpcodeVecI8x16SwizzleName.
-func newOperationV128Swizzle() unionOperation {
- return unionOperation{Kind: operationKindV128Swizzle}
-}
-
-// NewOperationV128AnyTrue is a constructor for unionOperation with operationKindV128AnyTrue.
-//
-// This corresponds to wasm.OpcodeVecV128AnyTrueName.
-func newOperationV128AnyTrue() unionOperation {
- return unionOperation{Kind: operationKindV128AnyTrue}
-}
-
-// NewOperationV128AllTrue is a constructor for unionOperation with operationKindV128AllTrue.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16AllTrueName wasm.OpcodeVecI16x8AllTrueName
-// wasm.OpcodeVecI32x4AllTrueName wasm.OpcodeVecI64x2AllTrueName.
-func newOperationV128AllTrue(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128AllTrue, B1: shape}
-}
-
-// NewOperationV128BitMask is a constructor for unionOperation with operationKindV128BitMask.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16BitMaskName wasm.OpcodeVecI16x8BitMaskName
-// wasm.OpcodeVecI32x4BitMaskName wasm.OpcodeVecI64x2BitMaskName.
-func newOperationV128BitMask(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128BitMask, B1: shape}
-}
-
-// NewOperationV128And is a constructor for unionOperation with operationKindV128And.
-//
-// This corresponds to wasm.OpcodeVecV128And.
-func newOperationV128And() unionOperation {
- return unionOperation{Kind: operationKindV128And}
-}
-
-// NewOperationV128Not is a constructor for unionOperation with operationKindV128Not.
-//
-// This corresponds to wasm.OpcodeVecV128Not.
-func newOperationV128Not() unionOperation {
- return unionOperation{Kind: operationKindV128Not}
-}
-
-// NewOperationV128Or is a constructor for unionOperation with operationKindV128Or.
-//
-// This corresponds to wasm.OpcodeVecV128Or.
-func newOperationV128Or() unionOperation {
- return unionOperation{Kind: operationKindV128Or}
-}
-
-// NewOperationV128Xor is a constructor for unionOperation with operationKindV128Xor.
-//
-// This corresponds to wasm.OpcodeVecV128Xor.
-func newOperationV128Xor() unionOperation {
- return unionOperation{Kind: operationKindV128Xor}
-}
-
-// NewOperationV128Bitselect is a constructor for unionOperation with operationKindV128Bitselect.
-//
-// This corresponds to wasm.OpcodeVecV128Bitselect.
-func newOperationV128Bitselect() unionOperation {
- return unionOperation{Kind: operationKindV128Bitselect}
-}
-
-// NewOperationV128AndNot is a constructor for unionOperation with operationKindV128AndNot.
-//
-// This corresponds to wasm.OpcodeVecV128AndNot.
-func newOperationV128AndNot() unionOperation {
- return unionOperation{Kind: operationKindV128AndNot}
-}
-
-// NewOperationV128Shl is a constructor for unionOperation with operationKindV128Shl.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16ShlName wasm.OpcodeVecI16x8ShlName
-// wasm.OpcodeVecI32x4ShlName wasm.OpcodeVecI64x2ShlName
-func newOperationV128Shl(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Shl, B1: shape}
-}
-
-// NewOperationV128Shr is a constructor for unionOperation with operationKindV128Shr.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16ShrSName wasm.OpcodeVecI8x16ShrUName wasm.OpcodeVecI16x8ShrSName
-// wasm.OpcodeVecI16x8ShrUName wasm.OpcodeVecI32x4ShrSName wasm.OpcodeVecI32x4ShrUName.
-// wasm.OpcodeVecI64x2ShrSName wasm.OpcodeVecI64x2ShrUName.
-func newOperationV128Shr(shape shape, signed bool) unionOperation {
- return unionOperation{Kind: operationKindV128Shr, B1: shape, B3: signed}
-}
-
-// NewOperationV128Cmp is a constructor for unionOperation with operationKindV128Cmp.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16EqName, wasm.OpcodeVecI8x16NeName, wasm.OpcodeVecI8x16LtSName, wasm.OpcodeVecI8x16LtUName, wasm.OpcodeVecI8x16GtSName,
-// wasm.OpcodeVecI8x16GtUName, wasm.OpcodeVecI8x16LeSName, wasm.OpcodeVecI8x16LeUName, wasm.OpcodeVecI8x16GeSName, wasm.OpcodeVecI8x16GeUName,
-// wasm.OpcodeVecI16x8EqName, wasm.OpcodeVecI16x8NeName, wasm.OpcodeVecI16x8LtSName, wasm.OpcodeVecI16x8LtUName, wasm.OpcodeVecI16x8GtSName,
-// wasm.OpcodeVecI16x8GtUName, wasm.OpcodeVecI16x8LeSName, wasm.OpcodeVecI16x8LeUName, wasm.OpcodeVecI16x8GeSName, wasm.OpcodeVecI16x8GeUName,
-// wasm.OpcodeVecI32x4EqName, wasm.OpcodeVecI32x4NeName, wasm.OpcodeVecI32x4LtSName, wasm.OpcodeVecI32x4LtUName, wasm.OpcodeVecI32x4GtSName,
-// wasm.OpcodeVecI32x4GtUName, wasm.OpcodeVecI32x4LeSName, wasm.OpcodeVecI32x4LeUName, wasm.OpcodeVecI32x4GeSName, wasm.OpcodeVecI32x4GeUName,
-// wasm.OpcodeVecI64x2EqName, wasm.OpcodeVecI64x2NeName, wasm.OpcodeVecI64x2LtSName, wasm.OpcodeVecI64x2GtSName, wasm.OpcodeVecI64x2LeSName,
-// wasm.OpcodeVecI64x2GeSName, wasm.OpcodeVecF32x4EqName, wasm.OpcodeVecF32x4NeName, wasm.OpcodeVecF32x4LtName, wasm.OpcodeVecF32x4GtName,
-// wasm.OpcodeVecF32x4LeName, wasm.OpcodeVecF32x4GeName, wasm.OpcodeVecF64x2EqName, wasm.OpcodeVecF64x2NeName, wasm.OpcodeVecF64x2LtName,
-// wasm.OpcodeVecF64x2GtName, wasm.OpcodeVecF64x2LeName, wasm.OpcodeVecF64x2GeName
-func newOperationV128Cmp(cmpType v128CmpType) unionOperation {
- return unionOperation{Kind: operationKindV128Cmp, B1: cmpType}
-}
-
-// v128CmpType represents a type of vector comparison operation.
-type v128CmpType = byte
-
-const (
- // v128CmpTypeI8x16Eq corresponds to wasm.OpcodeVecI8x16EqName.
- v128CmpTypeI8x16Eq v128CmpType = iota
- // v128CmpTypeI8x16Ne corresponds to wasm.OpcodeVecI8x16NeName.
- v128CmpTypeI8x16Ne
- // v128CmpTypeI8x16LtS corresponds to wasm.OpcodeVecI8x16LtSName.
- v128CmpTypeI8x16LtS
- // v128CmpTypeI8x16LtU corresponds to wasm.OpcodeVecI8x16LtUName.
- v128CmpTypeI8x16LtU
- // v128CmpTypeI8x16GtS corresponds to wasm.OpcodeVecI8x16GtSName.
- v128CmpTypeI8x16GtS
- // v128CmpTypeI8x16GtU corresponds to wasm.OpcodeVecI8x16GtUName.
- v128CmpTypeI8x16GtU
- // v128CmpTypeI8x16LeS corresponds to wasm.OpcodeVecI8x16LeSName.
- v128CmpTypeI8x16LeS
- // v128CmpTypeI8x16LeU corresponds to wasm.OpcodeVecI8x16LeUName.
- v128CmpTypeI8x16LeU
- // v128CmpTypeI8x16GeS corresponds to wasm.OpcodeVecI8x16GeSName.
- v128CmpTypeI8x16GeS
- // v128CmpTypeI8x16GeU corresponds to wasm.OpcodeVecI8x16GeUName.
- v128CmpTypeI8x16GeU
- // v128CmpTypeI16x8Eq corresponds to wasm.OpcodeVecI16x8EqName.
- v128CmpTypeI16x8Eq
- // v128CmpTypeI16x8Ne corresponds to wasm.OpcodeVecI16x8NeName.
- v128CmpTypeI16x8Ne
- // v128CmpTypeI16x8LtS corresponds to wasm.OpcodeVecI16x8LtSName.
- v128CmpTypeI16x8LtS
- // v128CmpTypeI16x8LtU corresponds to wasm.OpcodeVecI16x8LtUName.
- v128CmpTypeI16x8LtU
- // v128CmpTypeI16x8GtS corresponds to wasm.OpcodeVecI16x8GtSName.
- v128CmpTypeI16x8GtS
- // v128CmpTypeI16x8GtU corresponds to wasm.OpcodeVecI16x8GtUName.
- v128CmpTypeI16x8GtU
- // v128CmpTypeI16x8LeS corresponds to wasm.OpcodeVecI16x8LeSName.
- v128CmpTypeI16x8LeS
- // v128CmpTypeI16x8LeU corresponds to wasm.OpcodeVecI16x8LeUName.
- v128CmpTypeI16x8LeU
- // v128CmpTypeI16x8GeS corresponds to wasm.OpcodeVecI16x8GeSName.
- v128CmpTypeI16x8GeS
- // v128CmpTypeI16x8GeU corresponds to wasm.OpcodeVecI16x8GeUName.
- v128CmpTypeI16x8GeU
- // v128CmpTypeI32x4Eq corresponds to wasm.OpcodeVecI32x4EqName.
- v128CmpTypeI32x4Eq
- // v128CmpTypeI32x4Ne corresponds to wasm.OpcodeVecI32x4NeName.
- v128CmpTypeI32x4Ne
- // v128CmpTypeI32x4LtS corresponds to wasm.OpcodeVecI32x4LtSName.
- v128CmpTypeI32x4LtS
- // v128CmpTypeI32x4LtU corresponds to wasm.OpcodeVecI32x4LtUName.
- v128CmpTypeI32x4LtU
- // v128CmpTypeI32x4GtS corresponds to wasm.OpcodeVecI32x4GtSName.
- v128CmpTypeI32x4GtS
- // v128CmpTypeI32x4GtU corresponds to wasm.OpcodeVecI32x4GtUName.
- v128CmpTypeI32x4GtU
- // v128CmpTypeI32x4LeS corresponds to wasm.OpcodeVecI32x4LeSName.
- v128CmpTypeI32x4LeS
- // v128CmpTypeI32x4LeU corresponds to wasm.OpcodeVecI32x4LeUName.
- v128CmpTypeI32x4LeU
- // v128CmpTypeI32x4GeS corresponds to wasm.OpcodeVecI32x4GeSName.
- v128CmpTypeI32x4GeS
- // v128CmpTypeI32x4GeU corresponds to wasm.OpcodeVecI32x4GeUName.
- v128CmpTypeI32x4GeU
- // v128CmpTypeI64x2Eq corresponds to wasm.OpcodeVecI64x2EqName.
- v128CmpTypeI64x2Eq
- // v128CmpTypeI64x2Ne corresponds to wasm.OpcodeVecI64x2NeName.
- v128CmpTypeI64x2Ne
- // v128CmpTypeI64x2LtS corresponds to wasm.OpcodeVecI64x2LtSName.
- v128CmpTypeI64x2LtS
- // v128CmpTypeI64x2GtS corresponds to wasm.OpcodeVecI64x2GtSName.
- v128CmpTypeI64x2GtS
- // v128CmpTypeI64x2LeS corresponds to wasm.OpcodeVecI64x2LeSName.
- v128CmpTypeI64x2LeS
- // v128CmpTypeI64x2GeS corresponds to wasm.OpcodeVecI64x2GeSName.
- v128CmpTypeI64x2GeS
- // v128CmpTypeF32x4Eq corresponds to wasm.OpcodeVecF32x4EqName.
- v128CmpTypeF32x4Eq
- // v128CmpTypeF32x4Ne corresponds to wasm.OpcodeVecF32x4NeName.
- v128CmpTypeF32x4Ne
- // v128CmpTypeF32x4Lt corresponds to wasm.OpcodeVecF32x4LtName.
- v128CmpTypeF32x4Lt
- // v128CmpTypeF32x4Gt corresponds to wasm.OpcodeVecF32x4GtName.
- v128CmpTypeF32x4Gt
- // v128CmpTypeF32x4Le corresponds to wasm.OpcodeVecF32x4LeName.
- v128CmpTypeF32x4Le
- // v128CmpTypeF32x4Ge corresponds to wasm.OpcodeVecF32x4GeName.
- v128CmpTypeF32x4Ge
- // v128CmpTypeF64x2Eq corresponds to wasm.OpcodeVecF64x2EqName.
- v128CmpTypeF64x2Eq
- // v128CmpTypeF64x2Ne corresponds to wasm.OpcodeVecF64x2NeName.
- v128CmpTypeF64x2Ne
- // v128CmpTypeF64x2Lt corresponds to wasm.OpcodeVecF64x2LtName.
- v128CmpTypeF64x2Lt
- // v128CmpTypeF64x2Gt corresponds to wasm.OpcodeVecF64x2GtName.
- v128CmpTypeF64x2Gt
- // v128CmpTypeF64x2Le corresponds to wasm.OpcodeVecF64x2LeName.
- v128CmpTypeF64x2Le
- // v128CmpTypeF64x2Ge corresponds to wasm.OpcodeVecF64x2GeName.
- v128CmpTypeF64x2Ge
-)
-
-// NewOperationV128AddSat is a constructor for unionOperation with operationKindV128AddSat.
-//
-// This corresponds to wasm.OpcodeVecI8x16AddSatUName wasm.OpcodeVecI8x16AddSatSName
-//
-// wasm.OpcodeVecI16x8AddSatUName wasm.OpcodeVecI16x8AddSatSName
-//
-// shape is either shapeI8x16 or shapeI16x8.
-func newOperationV128AddSat(shape shape, signed bool) unionOperation {
- return unionOperation{Kind: operationKindV128AddSat, B1: shape, B3: signed}
-}
-
-// NewOperationV128SubSat is a constructor for unionOperation with operationKindV128SubSat.
-//
-// This corresponds to wasm.OpcodeVecI8x16SubSatUName wasm.OpcodeVecI8x16SubSatSName
-//
-// wasm.OpcodeVecI16x8SubSatUName wasm.OpcodeVecI16x8SubSatSName
-//
-// shape is either shapeI8x16 or shapeI16x8.
-func newOperationV128SubSat(shape shape, signed bool) unionOperation {
- return unionOperation{Kind: operationKindV128SubSat, B1: shape, B3: signed}
-}
-
-// NewOperationV128Mul is a constructor for unionOperation with operationKindV128Mul
-//
-// This corresponds to wasm.OpcodeVecF32x4MulName wasm.OpcodeVecF64x2MulName
-//
-// wasm.OpcodeVecI16x8MulName wasm.OpcodeVecI32x4MulName wasm.OpcodeVecI64x2MulName.
-// shape is either shapeI16x8, shapeI32x4, shapeI64x2, shapeF32x4 or shapeF64x2.
-func newOperationV128Mul(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Mul, B1: shape}
-}
-
-// NewOperationV128Div is a constructor for unionOperation with operationKindV128Div.
-//
-// This corresponds to wasm.OpcodeVecF32x4DivName wasm.OpcodeVecF64x2DivName.
-// shape is either shapeF32x4 or shapeF64x2.
-func newOperationV128Div(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Div, B1: shape}
-}
-
-// NewOperationV128Neg is a constructor for unionOperation with operationKindV128Neg.
-//
-// This corresponds to wasm.OpcodeVecI8x16NegName wasm.OpcodeVecI16x8NegName wasm.OpcodeVecI32x4NegName
-//
-// wasm.OpcodeVecI64x2NegName wasm.OpcodeVecF32x4NegName wasm.OpcodeVecF64x2NegName.
-func newOperationV128Neg(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Neg, B1: shape}
-}
-
-// NewOperationV128Sqrt is a constructor for unionOperation with 128operationKindV128Sqrt.
-//
-// shape is either shapeF32x4 or shapeF64x2.
-// This corresponds to wasm.OpcodeVecF32x4SqrtName wasm.OpcodeVecF64x2SqrtName.
-func newOperationV128Sqrt(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Sqrt, B1: shape}
-}
-
-// NewOperationV128Abs is a constructor for unionOperation with operationKindV128Abs.
-//
-// This corresponds to wasm.OpcodeVecI8x16AbsName wasm.OpcodeVecI16x8AbsName wasm.OpcodeVecI32x4AbsName
-//
-// wasm.OpcodeVecI64x2AbsName wasm.OpcodeVecF32x4AbsName wasm.OpcodeVecF64x2AbsName.
-func newOperationV128Abs(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Abs, B1: shape}
-}
-
-// NewOperationV128Popcnt is a constructor for unionOperation with operationKindV128Popcnt.
-//
-// This corresponds to wasm.OpcodeVecI8x16PopcntName.
-func newOperationV128Popcnt(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Popcnt, B1: shape}
-}
-
-// NewOperationV128Min is a constructor for unionOperation with operationKindV128Min.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16MinSName wasm.OpcodeVecI8x16MinUName wasm.OpcodeVecI16x8MinSName wasm.OpcodeVecI16x8MinUName
-// wasm.OpcodeVecI32x4MinSName wasm.OpcodeVecI32x4MinUName wasm.OpcodeVecI16x8MinSName wasm.OpcodeVecI16x8MinUName
-// wasm.OpcodeVecF32x4MinName wasm.OpcodeVecF64x2MinName
-func newOperationV128Min(shape shape, signed bool) unionOperation {
- return unionOperation{Kind: operationKindV128Min, B1: shape, B3: signed}
-}
-
-// NewOperationV128Max is a constructor for unionOperation with operationKindV128Max.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16MaxSName wasm.OpcodeVecI8x16MaxUName wasm.OpcodeVecI16x8MaxSName wasm.OpcodeVecI16x8MaxUName
-// wasm.OpcodeVecI32x4MaxSName wasm.OpcodeVecI32x4MaxUName wasm.OpcodeVecI16x8MaxSName wasm.OpcodeVecI16x8MaxUName
-// wasm.OpcodeVecF32x4MaxName wasm.OpcodeVecF64x2MaxName.
-func newOperationV128Max(shape shape, signed bool) unionOperation {
- return unionOperation{Kind: operationKindV128Max, B1: shape, B3: signed}
-}
-
-// NewOperationV128AvgrU is a constructor for unionOperation with operationKindV128AvgrU.
-//
-// This corresponds to wasm.OpcodeVecI8x16AvgrUName.
-func newOperationV128AvgrU(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128AvgrU, B1: shape}
-}
-
-// NewOperationV128Pmin is a constructor for unionOperation with operationKindV128Pmin.
-//
-// This corresponds to wasm.OpcodeVecF32x4PminName wasm.OpcodeVecF64x2PminName.
-func newOperationV128Pmin(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Pmin, B1: shape}
-}
-
-// NewOperationV128Pmax is a constructor for unionOperation with operationKindV128Pmax.
-//
-// This corresponds to wasm.OpcodeVecF32x4PmaxName wasm.OpcodeVecF64x2PmaxName.
-func newOperationV128Pmax(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Pmax, B1: shape}
-}
-
-// NewOperationV128Ceil is a constructor for unionOperation with operationKindV128Ceil.
-//
-// This corresponds to wasm.OpcodeVecF32x4CeilName wasm.OpcodeVecF64x2CeilName
-func newOperationV128Ceil(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Ceil, B1: shape}
-}
-
-// NewOperationV128Floor is a constructor for unionOperation with operationKindV128Floor.
-//
-// This corresponds to wasm.OpcodeVecF32x4FloorName wasm.OpcodeVecF64x2FloorName
-func newOperationV128Floor(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Floor, B1: shape}
-}
-
-// NewOperationV128Trunc is a constructor for unionOperation with operationKindV128Trunc.
-//
-// This corresponds to wasm.OpcodeVecF32x4TruncName wasm.OpcodeVecF64x2TruncName
-func newOperationV128Trunc(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Trunc, B1: shape}
-}
-
-// NewOperationV128Nearest is a constructor for unionOperation with operationKindV128Nearest.
-//
-// This corresponds to wasm.OpcodeVecF32x4NearestName wasm.OpcodeVecF64x2NearestName
-func newOperationV128Nearest(shape shape) unionOperation {
- return unionOperation{Kind: operationKindV128Nearest, B1: shape}
-}
-
-// NewOperationV128Extend is a constructor for unionOperation with operationKindV128Extend.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI16x8ExtendLowI8x16SName wasm.OpcodeVecI16x8ExtendHighI8x16SName
-// wasm.OpcodeVecI16x8ExtendLowI8x16UName wasm.OpcodeVecI16x8ExtendHighI8x16UName
-// wasm.OpcodeVecI32x4ExtendLowI16x8SName wasm.OpcodeVecI32x4ExtendHighI16x8SName
-// wasm.OpcodeVecI32x4ExtendLowI16x8UName wasm.OpcodeVecI32x4ExtendHighI16x8UName
-// wasm.OpcodeVecI64x2ExtendLowI32x4SName wasm.OpcodeVecI64x2ExtendHighI32x4SName
-// wasm.OpcodeVecI64x2ExtendLowI32x4UName wasm.OpcodeVecI64x2ExtendHighI32x4UName
-//
-// originshape is the shape of the original lanes for extension which is
-// either shapeI8x16, shapeI16x8, or shapeI32x4.
-// useLow true if it uses the lower half of vector for extension.
-func newOperationV128Extend(originshape shape, signed bool, useLow bool) unionOperation {
- op := unionOperation{Kind: operationKindV128Extend}
- op.B1 = originshape
- if signed {
- op.B2 = 1
- }
- op.B3 = useLow
- return op
-}
-
-// NewOperationV128ExtMul is a constructor for unionOperation with operationKindV128ExtMul.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI16x8ExtMulLowI8x16SName wasm.OpcodeVecI16x8ExtMulLowI8x16UName
-// wasm.OpcodeVecI16x8ExtMulHighI8x16SName wasm.OpcodeVecI16x8ExtMulHighI8x16UName
-// wasm.OpcodeVecI32x4ExtMulLowI16x8SName wasm.OpcodeVecI32x4ExtMulLowI16x8UName
-// wasm.OpcodeVecI32x4ExtMulHighI16x8SName wasm.OpcodeVecI32x4ExtMulHighI16x8UName
-// wasm.OpcodeVecI64x2ExtMulLowI32x4SName wasm.OpcodeVecI64x2ExtMulLowI32x4UName
-// wasm.OpcodeVecI64x2ExtMulHighI32x4SName wasm.OpcodeVecI64x2ExtMulHighI32x4UName.
-//
-// originshape is the shape of the original lanes for extension which is
-// either shapeI8x16, shapeI16x8, or shapeI32x4.
-// useLow true if it uses the lower half of vector for extension.
-func newOperationV128ExtMul(originshape shape, signed bool, useLow bool) unionOperation {
- op := unionOperation{Kind: operationKindV128ExtMul}
- op.B1 = originshape
- if signed {
- op.B2 = 1
- }
- op.B3 = useLow
- return op
-}
-
-// NewOperationV128Q15mulrSatS is a constructor for unionOperation with operationKindV128Q15mulrSatS.
-//
-// This corresponds to wasm.OpcodeVecI16x8Q15mulrSatSName
-func newOperationV128Q15mulrSatS() unionOperation {
- return unionOperation{Kind: operationKindV128Q15mulrSatS}
-}
-
-// NewOperationV128ExtAddPairwise is a constructor for unionOperation with operationKindV128ExtAddPairwise.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI16x8ExtaddPairwiseI8x16SName wasm.OpcodeVecI16x8ExtaddPairwiseI8x16UName
-// wasm.OpcodeVecI32x4ExtaddPairwiseI16x8SName wasm.OpcodeVecI32x4ExtaddPairwiseI16x8UName.
-//
-// originshape is the shape of the original lanes for extension which is
-// either shapeI8x16, or shapeI16x8.
-func newOperationV128ExtAddPairwise(originshape shape, signed bool) unionOperation {
- return unionOperation{Kind: operationKindV128ExtAddPairwise, B1: originshape, B3: signed}
-}
-
-// NewOperationV128FloatPromote is a constructor for unionOperation with NewOperationV128FloatPromote.
-//
-// This corresponds to wasm.OpcodeVecF64x2PromoteLowF32x4ZeroName
-// This discards the higher 64-bit of a vector, and promotes two
-// 32-bit floats in the lower 64-bit as two 64-bit floats.
-func newOperationV128FloatPromote() unionOperation {
- return unionOperation{Kind: operationKindV128FloatPromote}
-}
-
-// NewOperationV128FloatDemote is a constructor for unionOperation with NewOperationV128FloatDemote.
-//
-// This corresponds to wasm.OpcodeVecF32x4DemoteF64x2ZeroName.
-func newOperationV128FloatDemote() unionOperation {
- return unionOperation{Kind: operationKindV128FloatDemote}
-}
-
-// NewOperationV128FConvertFromI is a constructor for unionOperation with NewOperationV128FConvertFromI.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecF32x4ConvertI32x4SName wasm.OpcodeVecF32x4ConvertI32x4UName
-// wasm.OpcodeVecF64x2ConvertLowI32x4SName wasm.OpcodeVecF64x2ConvertLowI32x4UName.
-//
-// destinationshape is the shape of the destination lanes for conversion which is
-// either shapeF32x4, or shapeF64x2.
-func newOperationV128FConvertFromI(destinationshape shape, signed bool) unionOperation {
- return unionOperation{Kind: operationKindV128FConvertFromI, B1: destinationshape, B3: signed}
-}
-
-// NewOperationV128Dot is a constructor for unionOperation with operationKindV128Dot.
-//
-// This corresponds to wasm.OpcodeVecI32x4DotI16x8SName
-func newOperationV128Dot() unionOperation {
- return unionOperation{Kind: operationKindV128Dot}
-}
-
-// NewOperationV128Narrow is a constructor for unionOperation with operationKindV128Narrow.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI8x16NarrowI16x8SName wasm.OpcodeVecI8x16NarrowI16x8UName
-// wasm.OpcodeVecI16x8NarrowI32x4SName wasm.OpcodeVecI16x8NarrowI32x4UName.
-//
-// originshape is the shape of the original lanes for narrowing which is
-// either shapeI16x8, or shapeI32x4.
-func newOperationV128Narrow(originshape shape, signed bool) unionOperation {
- return unionOperation{Kind: operationKindV128Narrow, B1: originshape, B3: signed}
-}
-
-// NewOperationV128ITruncSatFromF is a constructor for unionOperation with operationKindV128ITruncSatFromF.
-//
-// This corresponds to
-//
-// wasm.OpcodeVecI32x4TruncSatF64x2UZeroName wasm.OpcodeVecI32x4TruncSatF64x2SZeroName
-// wasm.OpcodeVecI32x4TruncSatF32x4UName wasm.OpcodeVecI32x4TruncSatF32x4SName.
-//
-// originshape is the shape of the original lanes for truncation which is
-// either shapeF32x4, or shapeF64x2.
-func newOperationV128ITruncSatFromF(originshape shape, signed bool) unionOperation {
- return unionOperation{Kind: operationKindV128ITruncSatFromF, B1: originshape, B3: signed}
-}
-
-// atomicArithmeticOp is the type for the operation kind of atomic arithmetic operations.
-type atomicArithmeticOp byte
-
-const (
- // atomicArithmeticOpAdd is the kind for an add operation.
- atomicArithmeticOpAdd atomicArithmeticOp = iota
- // atomicArithmeticOpSub is the kind for a sub operation.
- atomicArithmeticOpSub
- // atomicArithmeticOpAnd is the kind for a bitwise and operation.
- atomicArithmeticOpAnd
- // atomicArithmeticOpOr is the kind for a bitwise or operation.
- atomicArithmeticOpOr
- // atomicArithmeticOpXor is the kind for a bitwise xor operation.
- atomicArithmeticOpXor
- // atomicArithmeticOpNop is the kind for a nop operation.
- atomicArithmeticOpNop
-)
-
-// NewOperationAtomicMemoryWait is a constructor for unionOperation with operationKindAtomicMemoryWait.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicWait32Name wasm.OpcodeAtomicWait64Name
-func newOperationAtomicMemoryWait(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicMemoryWait, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicMemoryNotify is a constructor for unionOperation with operationKindAtomicMemoryNotify.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicNotifyName
-func newOperationAtomicMemoryNotify(arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicMemoryNotify, U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicFence is a constructor for unionOperation with operationKindAtomicFence.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicFenceName
-func newOperationAtomicFence() unionOperation {
- return unionOperation{Kind: operationKindAtomicFence}
-}
-
-// NewOperationAtomicLoad is a constructor for unionOperation with operationKindAtomicLoad.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32LoadName wasm.OpcodeAtomicI64LoadName
-func newOperationAtomicLoad(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicLoad, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicLoad8 is a constructor for unionOperation with operationKindAtomicLoad8.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32Load8UName wasm.OpcodeAtomicI64Load8UName
-func newOperationAtomicLoad8(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicLoad8, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicLoad16 is a constructor for unionOperation with operationKindAtomicLoad16.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32Load16UName wasm.OpcodeAtomicI64Load16UName
-func newOperationAtomicLoad16(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicLoad16, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicStore is a constructor for unionOperation with operationKindAtomicStore.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32StoreName wasm.OpcodeAtomicI64StoreName
-func newOperationAtomicStore(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicStore, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicStore8 is a constructor for unionOperation with operationKindAtomicStore8.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32Store8UName wasm.OpcodeAtomicI64Store8UName
-func newOperationAtomicStore8(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicStore8, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicStore16 is a constructor for unionOperation with operationKindAtomicStore16.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32Store16UName wasm.OpcodeAtomicI64Store16UName
-func newOperationAtomicStore16(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicStore16, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicRMW is a constructor for unionOperation with operationKindAtomicRMW.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32RMWAddName wasm.OpcodeAtomicI64RmwAddName
-// wasm.OpcodeAtomicI32RMWSubName wasm.OpcodeAtomicI64RmwSubName
-// wasm.OpcodeAtomicI32RMWAndName wasm.OpcodeAtomicI64RmwAndName
-// wasm.OpcodeAtomicI32RMWOrName wasm.OpcodeAtomicI64RmwOrName
-// wasm.OpcodeAtomicI32RMWXorName wasm.OpcodeAtomicI64RmwXorName
-func newOperationAtomicRMW(unsignedType unsignedType, arg memoryArg, op atomicArithmeticOp) unionOperation {
- return unionOperation{Kind: operationKindAtomicRMW, B1: byte(unsignedType), B2: byte(op), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicRMW8 is a constructor for unionOperation with operationKindAtomicRMW8.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32RMW8AddUName wasm.OpcodeAtomicI64Rmw8AddUName
-// wasm.OpcodeAtomicI32RMW8SubUName wasm.OpcodeAtomicI64Rmw8SubUName
-// wasm.OpcodeAtomicI32RMW8AndUName wasm.OpcodeAtomicI64Rmw8AndUName
-// wasm.OpcodeAtomicI32RMW8OrUName wasm.OpcodeAtomicI64Rmw8OrUName
-// wasm.OpcodeAtomicI32RMW8XorUName wasm.OpcodeAtomicI64Rmw8XorUName
-func newOperationAtomicRMW8(unsignedType unsignedType, arg memoryArg, op atomicArithmeticOp) unionOperation {
- return unionOperation{Kind: operationKindAtomicRMW8, B1: byte(unsignedType), B2: byte(op), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicRMW16 is a constructor for unionOperation with operationKindAtomicRMW16.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32RMW16AddUName wasm.OpcodeAtomicI64Rmw16AddUName
-// wasm.OpcodeAtomicI32RMW16SubUName wasm.OpcodeAtomicI64Rmw16SubUName
-// wasm.OpcodeAtomicI32RMW16AndUName wasm.OpcodeAtomicI64Rmw16AndUName
-// wasm.OpcodeAtomicI32RMW16OrUName wasm.OpcodeAtomicI64Rmw16OrUName
-// wasm.OpcodeAtomicI32RMW16XorUName wasm.OpcodeAtomicI64Rmw16XorUName
-func newOperationAtomicRMW16(unsignedType unsignedType, arg memoryArg, op atomicArithmeticOp) unionOperation {
- return unionOperation{Kind: operationKindAtomicRMW16, B1: byte(unsignedType), B2: byte(op), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicRMWCmpxchg is a constructor for unionOperation with operationKindAtomicRMWCmpxchg.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32RMWCmpxchgName wasm.OpcodeAtomicI64RmwCmpxchgName
-func newOperationAtomicRMWCmpxchg(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicRMWCmpxchg, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicRMW8Cmpxchg is a constructor for unionOperation with operationKindAtomicRMW8Cmpxchg.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32RMW8CmpxchgUName wasm.OpcodeAtomicI64Rmw8CmpxchgUName
-func newOperationAtomicRMW8Cmpxchg(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicRMW8Cmpxchg, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
-
-// NewOperationAtomicRMW16Cmpxchg is a constructor for unionOperation with operationKindAtomicRMW16Cmpxchg.
-//
-// This corresponds to
-//
-// wasm.OpcodeAtomicI32RMW16CmpxchgUName wasm.OpcodeAtomicI64Rmw16CmpxchgUName
-func newOperationAtomicRMW16Cmpxchg(unsignedType unsignedType, arg memoryArg) unionOperation {
- return unionOperation{Kind: operationKindAtomicRMW16Cmpxchg, B1: byte(unsignedType), U1: uint64(arg.Alignment), U2: uint64(arg.Offset)}
-}
diff --git a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/signature.go b/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/signature.go
deleted file mode 100644
index 7b9d5602d..000000000
--- a/vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/signature.go
+++ /dev/null
@@ -1,767 +0,0 @@
-package interpreter
-
-import (
- "fmt"
-
- "github.com/tetratelabs/wazero/internal/wasm"
-)
-
-// signature represents how a Wasm opcode
-// manipulates the value stacks in terms of value types.
-type signature struct {
- in, out []unsignedType
-}
-
-var (
- signature_None_None = &signature{}
- signature_Unknown_None = &signature{
- in: []unsignedType{unsignedTypeUnknown},
- }
- signature_None_I32 = &signature{
- out: []unsignedType{unsignedTypeI32},
- }
- signature_None_I64 = &signature{
- out: []unsignedType{unsignedTypeI64},
- }
- signature_None_V128 = &signature{
- out: []unsignedType{unsignedTypeV128},
- }
- signature_None_F32 = &signature{
- out: []unsignedType{unsignedTypeF32},
- }
- signature_None_F64 = &signature{
- out: []unsignedType{unsignedTypeF64},
- }
- signature_I32_None = &signature{
- in: []unsignedType{unsignedTypeI32},
- }
- signature_I64_None = &signature{
- in: []unsignedType{unsignedTypeI64},
- }
- signature_F32_None = &signature{
- in: []unsignedType{unsignedTypeF32},
- }
- signature_F64_None = &signature{
- in: []unsignedType{unsignedTypeF64},
- }
- signature_V128_None = &signature{
- in: []unsignedType{unsignedTypeV128},
- }
- signature_I32_I32 = &signature{
- in: []unsignedType{unsignedTypeI32},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_I32_I64 = &signature{
- in: []unsignedType{unsignedTypeI32},
- out: []unsignedType{unsignedTypeI64},
- }
- signature_I64_I64 = &signature{
- in: []unsignedType{unsignedTypeI64},
- out: []unsignedType{unsignedTypeI64},
- }
- signature_I32_F32 = &signature{
- in: []unsignedType{unsignedTypeI32},
- out: []unsignedType{unsignedTypeF32},
- }
- signature_I32_F64 = &signature{
- in: []unsignedType{unsignedTypeI32},
- out: []unsignedType{unsignedTypeF64},
- }
- signature_I64_I32 = &signature{
- in: []unsignedType{unsignedTypeI64},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_I64_F32 = &signature{
- in: []unsignedType{unsignedTypeI64},
- out: []unsignedType{unsignedTypeF32},
- }
- signature_I64_F64 = &signature{
- in: []unsignedType{unsignedTypeI64},
- out: []unsignedType{unsignedTypeF64},
- }
- signature_F32_I32 = &signature{
- in: []unsignedType{unsignedTypeF32},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_F32_I64 = &signature{
- in: []unsignedType{unsignedTypeF32},
- out: []unsignedType{unsignedTypeI64},
- }
- signature_F32_F64 = &signature{
- in: []unsignedType{unsignedTypeF32},
- out: []unsignedType{unsignedTypeF64},
- }
- signature_F32_F32 = &signature{
- in: []unsignedType{unsignedTypeF32},
- out: []unsignedType{unsignedTypeF32},
- }
- signature_F64_I32 = &signature{
- in: []unsignedType{unsignedTypeF64},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_F64_F32 = &signature{
- in: []unsignedType{unsignedTypeF64},
- out: []unsignedType{unsignedTypeF32},
- }
- signature_F64_I64 = &signature{
- in: []unsignedType{unsignedTypeF64},
- out: []unsignedType{unsignedTypeI64},
- }
- signature_F64_F64 = &signature{
- in: []unsignedType{unsignedTypeF64},
- out: []unsignedType{unsignedTypeF64},
- }
- signature_I32I32_None = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI32},
- }
-
- signature_I32I32_I32 = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI32},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_I32I64_None = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI64},
- }
- signature_I32F32_None = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeF32},
- }
- signature_I32F64_None = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeF64},
- }
- signature_I64I32_I32 = &signature{
- in: []unsignedType{unsignedTypeI64, unsignedTypeI32},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_I64I64_I32 = &signature{
- in: []unsignedType{unsignedTypeI64, unsignedTypeI64},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_I64I64_I64 = &signature{
- in: []unsignedType{unsignedTypeI64, unsignedTypeI64},
- out: []unsignedType{unsignedTypeI64},
- }
- signature_F32F32_I32 = &signature{
- in: []unsignedType{unsignedTypeF32, unsignedTypeF32},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_F32F32_F32 = &signature{
- in: []unsignedType{unsignedTypeF32, unsignedTypeF32},
- out: []unsignedType{unsignedTypeF32},
- }
- signature_F64F64_I32 = &signature{
- in: []unsignedType{unsignedTypeF64, unsignedTypeF64},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_F64F64_F64 = &signature{
- in: []unsignedType{unsignedTypeF64, unsignedTypeF64},
- out: []unsignedType{unsignedTypeF64},
- }
- signature_I32I32I32_None = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI32, unsignedTypeI32},
- }
- signature_I32I64I32_None = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI64, unsignedTypeI32},
- }
- signature_UnknownUnknownI32_Unknown = &signature{
- in: []unsignedType{unsignedTypeUnknown, unsignedTypeUnknown, unsignedTypeI32},
- out: []unsignedType{unsignedTypeUnknown},
- }
- signature_V128V128_V128 = &signature{
- in: []unsignedType{unsignedTypeV128, unsignedTypeV128},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_V128V128V128_V32 = &signature{
- in: []unsignedType{unsignedTypeV128, unsignedTypeV128, unsignedTypeV128},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_I32_V128 = &signature{
- in: []unsignedType{unsignedTypeI32},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_I32V128_None = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeV128},
- }
- signature_I32V128_V128 = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeV128},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_V128I32_V128 = &signature{
- in: []unsignedType{unsignedTypeV128, unsignedTypeI32},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_V128I64_V128 = &signature{
- in: []unsignedType{unsignedTypeV128, unsignedTypeI64},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_V128F32_V128 = &signature{
- in: []unsignedType{unsignedTypeV128, unsignedTypeF32},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_V128F64_V128 = &signature{
- in: []unsignedType{unsignedTypeV128, unsignedTypeF64},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_V128_I32 = &signature{
- in: []unsignedType{unsignedTypeV128},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_V128_I64 = &signature{
- in: []unsignedType{unsignedTypeV128},
- out: []unsignedType{unsignedTypeI64},
- }
- signature_V128_F32 = &signature{
- in: []unsignedType{unsignedTypeV128},
- out: []unsignedType{unsignedTypeF32},
- }
- signature_V128_F64 = &signature{
- in: []unsignedType{unsignedTypeV128},
- out: []unsignedType{unsignedTypeF64},
- }
- signature_V128_V128 = &signature{
- in: []unsignedType{unsignedTypeV128},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_I64_V128 = &signature{
- in: []unsignedType{unsignedTypeI64},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_F32_V128 = &signature{
- in: []unsignedType{unsignedTypeF32},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_F64_V128 = &signature{
- in: []unsignedType{unsignedTypeF64},
- out: []unsignedType{unsignedTypeV128},
- }
- signature_I32I64_I64 = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI64},
- out: []unsignedType{unsignedTypeI64},
- }
- signature_I32I32I64_I32 = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI32, unsignedTypeI64},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_I32I64I64_I32 = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI64, unsignedTypeI64},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_I32I32I32_I32 = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI32, unsignedTypeI32},
- out: []unsignedType{unsignedTypeI32},
- }
- signature_I32I64I64_I64 = &signature{
- in: []unsignedType{unsignedTypeI32, unsignedTypeI64, unsignedTypeI64},
- out: []unsignedType{unsignedTypeI64},
- }
-)
-
-// wasmOpcodeSignature returns the signature of given Wasm opcode.
-// Note that some of opcodes' signature vary depending on
-// the function instance (for example, local types).
-// "index" parameter is not used by most of opcodes.
-// The returned signature is used for stack validation when lowering Wasm's opcodes to interpreterir.
-func (c *compiler) wasmOpcodeSignature(op wasm.Opcode, index uint32) (*signature, error) {
- switch op {
- case wasm.OpcodeUnreachable, wasm.OpcodeNop, wasm.OpcodeBlock, wasm.OpcodeLoop:
- return signature_None_None, nil
- case wasm.OpcodeIf:
- return signature_I32_None, nil
- case wasm.OpcodeElse, wasm.OpcodeEnd, wasm.OpcodeBr:
- return signature_None_None, nil
- case wasm.OpcodeBrIf, wasm.OpcodeBrTable:
- return signature_I32_None, nil
- case wasm.OpcodeReturn:
- return signature_None_None, nil
- case wasm.OpcodeCall:
- return c.funcTypeToSigs.get(c.funcs[index], false /* direct */), nil
- case wasm.OpcodeCallIndirect:
- return c.funcTypeToSigs.get(index, true /* call_indirect */), nil
- case wasm.OpcodeDrop:
- return signature_Unknown_None, nil
- case wasm.OpcodeSelect, wasm.OpcodeTypedSelect:
- return signature_UnknownUnknownI32_Unknown, nil
- case wasm.OpcodeLocalGet:
- inputLen := uint32(len(c.sig.Params))
- if l := uint32(len(c.localTypes)) + inputLen; index >= l {
- return nil, fmt.Errorf("invalid local index for local.get %d >= %d", index, l)
- }
- var t wasm.ValueType
- if index < inputLen {
- t = c.sig.Params[index]
- } else {
- t = c.localTypes[index-inputLen]
- }
- return wasmValueTypeToUnsignedOutSignature(t), nil
- case wasm.OpcodeLocalSet:
- inputLen := uint32(len(c.sig.Params))
- if l := uint32(len(c.localTypes)) + inputLen; index >= l {
- return nil, fmt.Errorf("invalid local index for local.get %d >= %d", index, l)
- }
- var t wasm.ValueType
- if index < inputLen {
- t = c.sig.Params[index]
- } else {
- t = c.localTypes[index-inputLen]
- }
- return wasmValueTypeToUnsignedInSignature(t), nil
- case wasm.OpcodeLocalTee:
- inputLen := uint32(len(c.sig.Params))
- if l := uint32(len(c.localTypes)) + inputLen; index >= l {
- return nil, fmt.Errorf("invalid local index for local.get %d >= %d", index, l)
- }
- var t wasm.ValueType
- if index < inputLen {
- t = c.sig.Params[index]
- } else {
- t = c.localTypes[index-inputLen]
- }
- return wasmValueTypeToUnsignedInOutSignature(t), nil
- case wasm.OpcodeGlobalGet:
- if len(c.globals) <= int(index) {
- return nil, fmt.Errorf("invalid global index for global.get %d >= %d", index, len(c.globals))
- }
- return wasmValueTypeToUnsignedOutSignature(c.globals[index].ValType), nil
- case wasm.OpcodeGlobalSet:
- if len(c.globals) <= int(index) {
- return nil, fmt.Errorf("invalid global index for global.get %d >= %d", index, len(c.globals))
- }
- return wasmValueTypeToUnsignedInSignature(c.globals[index].ValType), nil
- case wasm.OpcodeI32Load:
- return signature_I32_I32, nil
- case wasm.OpcodeI64Load:
- return signature_I32_I64, nil
- case wasm.OpcodeF32Load:
- return signature_I32_F32, nil
- case wasm.OpcodeF64Load:
- return signature_I32_F64, nil
- case wasm.OpcodeI32Load8S, wasm.OpcodeI32Load8U, wasm.OpcodeI32Load16S, wasm.OpcodeI32Load16U:
- return signature_I32_I32, nil
- case wasm.OpcodeI64Load8S, wasm.OpcodeI64Load8U, wasm.OpcodeI64Load16S, wasm.OpcodeI64Load16U,
- wasm.OpcodeI64Load32S, wasm.OpcodeI64Load32U:
- return signature_I32_I64, nil
- case wasm.OpcodeI32Store:
- return signature_I32I32_None, nil
- case wasm.OpcodeI64Store:
- return signature_I32I64_None, nil
- case wasm.OpcodeF32Store:
- return signature_I32F32_None, nil
- case wasm.OpcodeF64Store:
- return signature_I32F64_None, nil
- case wasm.OpcodeI32Store8:
- return signature_I32I32_None, nil
- case wasm.OpcodeI32Store16:
- return signature_I32I32_None, nil
- case wasm.OpcodeI64Store8:
- return signature_I32I64_None, nil
- case wasm.OpcodeI64Store16:
- return signature_I32I64_None, nil
- case wasm.OpcodeI64Store32:
- return signature_I32I64_None, nil
- case wasm.OpcodeMemorySize:
- return signature_None_I32, nil
- case wasm.OpcodeMemoryGrow:
- return signature_I32_I32, nil
- case wasm.OpcodeI32Const:
- return signature_None_I32, nil
- case wasm.OpcodeI64Const:
- return signature_None_I64, nil
- case wasm.OpcodeF32Const:
- return signature_None_F32, nil
- case wasm.OpcodeF64Const:
- return signature_None_F64, nil
- case wasm.OpcodeI32Eqz:
- return signature_I32_I32, nil
- case wasm.OpcodeI32Eq, wasm.OpcodeI32Ne, wasm.OpcodeI32LtS,
- wasm.OpcodeI32LtU, wasm.OpcodeI32GtS, wasm.OpcodeI32GtU,
- wasm.OpcodeI32LeS, wasm.OpcodeI32LeU, wasm.OpcodeI32GeS,
- wasm.OpcodeI32GeU:
- return signature_I32I32_I32, nil
- case wasm.OpcodeI64Eqz:
- return signature_I64_I32, nil
- case wasm.OpcodeI64Eq, wasm.OpcodeI64Ne, wasm.OpcodeI64LtS,
- wasm.OpcodeI64LtU, wasm.OpcodeI64GtS, wasm.OpcodeI64GtU,
- wasm.OpcodeI64LeS, wasm.OpcodeI64LeU, wasm.OpcodeI64GeS,
- wasm.OpcodeI64GeU:
- return signature_I64I64_I32, nil
- case wasm.OpcodeF32Eq, wasm.OpcodeF32Ne, wasm.OpcodeF32Lt,
- wasm.OpcodeF32Gt, wasm.OpcodeF32Le, wasm.OpcodeF32Ge:
- return signature_F32F32_I32, nil
- case wasm.OpcodeF64Eq, wasm.OpcodeF64Ne, wasm.OpcodeF64Lt,
- wasm.OpcodeF64Gt, wasm.OpcodeF64Le, wasm.OpcodeF64Ge:
- return signature_F64F64_I32, nil
- case wasm.OpcodeI32Clz, wasm.OpcodeI32Ctz, wasm.OpcodeI32Popcnt:
- return signature_I32_I32, nil
- case wasm.OpcodeI32Add, wasm.OpcodeI32Sub, wasm.OpcodeI32Mul,
- wasm.OpcodeI32DivS, wasm.OpcodeI32DivU, wasm.OpcodeI32RemS,
- wasm.OpcodeI32RemU, wasm.OpcodeI32And, wasm.OpcodeI32Or,
- wasm.OpcodeI32Xor, wasm.OpcodeI32Shl, wasm.OpcodeI32ShrS,
- wasm.OpcodeI32ShrU, wasm.OpcodeI32Rotl, wasm.OpcodeI32Rotr:
- return signature_I32I32_I32, nil
- case wasm.OpcodeI64Clz, wasm.OpcodeI64Ctz, wasm.OpcodeI64Popcnt:
- return signature_I64_I64, nil
- case wasm.OpcodeI64Add, wasm.OpcodeI64Sub, wasm.OpcodeI64Mul,
- wasm.OpcodeI64DivS, wasm.OpcodeI64DivU, wasm.OpcodeI64RemS,
- wasm.OpcodeI64RemU, wasm.OpcodeI64And, wasm.OpcodeI64Or,
- wasm.OpcodeI64Xor, wasm.OpcodeI64Shl, wasm.OpcodeI64ShrS,
- wasm.OpcodeI64ShrU, wasm.OpcodeI64Rotl, wasm.OpcodeI64Rotr:
- return signature_I64I64_I64, nil
- case wasm.OpcodeF32Abs, wasm.OpcodeF32Neg, wasm.OpcodeF32Ceil,
- wasm.OpcodeF32Floor, wasm.OpcodeF32Trunc, wasm.OpcodeF32Nearest,
- wasm.OpcodeF32Sqrt:
- return signature_F32_F32, nil
- case wasm.OpcodeF32Add, wasm.OpcodeF32Sub, wasm.OpcodeF32Mul,
- wasm.OpcodeF32Div, wasm.OpcodeF32Min, wasm.OpcodeF32Max,
- wasm.OpcodeF32Copysign:
- return signature_F32F32_F32, nil
- case wasm.OpcodeF64Abs, wasm.OpcodeF64Neg, wasm.OpcodeF64Ceil,
- wasm.OpcodeF64Floor, wasm.OpcodeF64Trunc, wasm.OpcodeF64Nearest,
- wasm.OpcodeF64Sqrt:
- return signature_F64_F64, nil
- case wasm.OpcodeF64Add, wasm.OpcodeF64Sub, wasm.OpcodeF64Mul,
- wasm.OpcodeF64Div, wasm.OpcodeF64Min, wasm.OpcodeF64Max,
- wasm.OpcodeF64Copysign:
- return signature_F64F64_F64, nil
- case wasm.OpcodeI32WrapI64:
- return signature_I64_I32, nil
- case wasm.OpcodeI32TruncF32S, wasm.OpcodeI32TruncF32U:
- return signature_F32_I32, nil
- case wasm.OpcodeI32TruncF64S, wasm.OpcodeI32TruncF64U:
- return signature_F64_I32, nil
- case wasm.OpcodeI64ExtendI32S, wasm.OpcodeI64ExtendI32U:
- return signature_I32_I64, nil
- case wasm.OpcodeI64TruncF32S, wasm.OpcodeI64TruncF32U:
- return signature_F32_I64, nil
- case wasm.OpcodeI64TruncF64S, wasm.OpcodeI64TruncF64U:
- return signature_F64_I64, nil
- case wasm.OpcodeF32ConvertI32S, wasm.OpcodeF32ConvertI32U:
- return signature_I32_F32, nil
- case wasm.OpcodeF32ConvertI64S, wasm.OpcodeF32ConvertI64U:
- return signature_I64_F32, nil
- case wasm.OpcodeF32DemoteF64:
- return signature_F64_F32, nil
- case wasm.OpcodeF64ConvertI32S, wasm.OpcodeF64ConvertI32U:
- return signature_I32_F64, nil
- case wasm.OpcodeF64ConvertI64S, wasm.OpcodeF64ConvertI64U:
- return signature_I64_F64, nil
- case wasm.OpcodeF64PromoteF32:
- return signature_F32_F64, nil
- case wasm.OpcodeI32ReinterpretF32:
- return signature_F32_I32, nil
- case wasm.OpcodeI64ReinterpretF64:
- return signature_F64_I64, nil
- case wasm.OpcodeF32ReinterpretI32:
- return signature_I32_F32, nil
- case wasm.OpcodeF64ReinterpretI64:
- return signature_I64_F64, nil
- case wasm.OpcodeI32Extend8S, wasm.OpcodeI32Extend16S:
- return signature_I32_I32, nil
- case wasm.OpcodeI64Extend8S, wasm.OpcodeI64Extend16S, wasm.OpcodeI64Extend32S:
- return signature_I64_I64, nil
- case wasm.OpcodeTableGet:
- // table.get takes table's offset and pushes the ref type value of opaque pointer as i64 value onto the stack.
- return signature_I32_I64, nil
- case wasm.OpcodeTableSet:
- // table.set takes table's offset and the ref type value of opaque pointer as i64 value.
- return signature_I32I64_None, nil
- case wasm.OpcodeRefFunc:
- // ref.func is translated as pushing the compiled function's opaque pointer (uint64) at interpreterir layer.
- return signature_None_I64, nil
- case wasm.OpcodeRefIsNull:
- // ref.is_null is translated as checking if the uint64 on the top of the stack (opaque pointer) is zero or not.
- return signature_I64_I32, nil
- case wasm.OpcodeRefNull:
- // ref.null is translated as i64.const 0.
- return signature_None_I64, nil
- case wasm.OpcodeMiscPrefix:
- switch miscOp := c.body[c.pc+1]; miscOp {
- case wasm.OpcodeMiscI32TruncSatF32S, wasm.OpcodeMiscI32TruncSatF32U:
- return signature_F32_I32, nil
- case wasm.OpcodeMiscI32TruncSatF64S, wasm.OpcodeMiscI32TruncSatF64U:
- return signature_F64_I32, nil
- case wasm.OpcodeMiscI64TruncSatF32S, wasm.OpcodeMiscI64TruncSatF32U:
- return signature_F32_I64, nil
- case wasm.OpcodeMiscI64TruncSatF64S, wasm.OpcodeMiscI64TruncSatF64U:
- return signature_F64_I64, nil
- case wasm.OpcodeMiscMemoryInit, wasm.OpcodeMiscMemoryCopy, wasm.OpcodeMiscMemoryFill,
- wasm.OpcodeMiscTableInit, wasm.OpcodeMiscTableCopy:
- return signature_I32I32I32_None, nil
- case wasm.OpcodeMiscDataDrop, wasm.OpcodeMiscElemDrop:
- return signature_None_None, nil
- case wasm.OpcodeMiscTableGrow:
- return signature_I64I32_I32, nil
- case wasm.OpcodeMiscTableSize:
- return signature_None_I32, nil
- case wasm.OpcodeMiscTableFill:
- return signature_I32I64I32_None, nil
- default:
- return nil, fmt.Errorf("unsupported misc instruction in interpreterir: 0x%x", op)
- }
- case wasm.OpcodeVecPrefix:
- switch vecOp := c.body[c.pc+1]; vecOp {
- case wasm.OpcodeVecV128Const:
- return signature_None_V128, nil
- case wasm.OpcodeVecV128Load, wasm.OpcodeVecV128Load8x8s, wasm.OpcodeVecV128Load8x8u,
- wasm.OpcodeVecV128Load16x4s, wasm.OpcodeVecV128Load16x4u, wasm.OpcodeVecV128Load32x2s,
- wasm.OpcodeVecV128Load32x2u, wasm.OpcodeVecV128Load8Splat, wasm.OpcodeVecV128Load16Splat,
- wasm.OpcodeVecV128Load32Splat, wasm.OpcodeVecV128Load64Splat, wasm.OpcodeVecV128Load32zero,
- wasm.OpcodeVecV128Load64zero:
- return signature_I32_V128, nil
- case wasm.OpcodeVecV128Load8Lane, wasm.OpcodeVecV128Load16Lane,
- wasm.OpcodeVecV128Load32Lane, wasm.OpcodeVecV128Load64Lane:
- return signature_I32V128_V128, nil
- case wasm.OpcodeVecV128Store,
- wasm.OpcodeVecV128Store8Lane,
- wasm.OpcodeVecV128Store16Lane,
- wasm.OpcodeVecV128Store32Lane,
- wasm.OpcodeVecV128Store64Lane:
- return signature_I32V128_None, nil
- case wasm.OpcodeVecI8x16ExtractLaneS,
- wasm.OpcodeVecI8x16ExtractLaneU,
- wasm.OpcodeVecI16x8ExtractLaneS,
- wasm.OpcodeVecI16x8ExtractLaneU,
- wasm.OpcodeVecI32x4ExtractLane:
- return signature_V128_I32, nil
- case wasm.OpcodeVecI64x2ExtractLane:
- return signature_V128_I64, nil
- case wasm.OpcodeVecF32x4ExtractLane:
- return signature_V128_F32, nil
- case wasm.OpcodeVecF64x2ExtractLane:
- return signature_V128_F64, nil
- case wasm.OpcodeVecI8x16ReplaceLane, wasm.OpcodeVecI16x8ReplaceLane, wasm.OpcodeVecI32x4ReplaceLane,
- wasm.OpcodeVecI8x16Shl, wasm.OpcodeVecI8x16ShrS, wasm.OpcodeVecI8x16ShrU,
- wasm.OpcodeVecI16x8Shl, wasm.OpcodeVecI16x8ShrS, wasm.OpcodeVecI16x8ShrU,
- wasm.OpcodeVecI32x4Shl, wasm.OpcodeVecI32x4ShrS, wasm.OpcodeVecI32x4ShrU,
- wasm.OpcodeVecI64x2Shl, wasm.OpcodeVecI64x2ShrS, wasm.OpcodeVecI64x2ShrU:
- return signature_V128I32_V128, nil
- case wasm.OpcodeVecI64x2ReplaceLane:
- return signature_V128I64_V128, nil
- case wasm.OpcodeVecF32x4ReplaceLane:
- return signature_V128F32_V128, nil
- case wasm.OpcodeVecF64x2ReplaceLane:
- return signature_V128F64_V128, nil
- case wasm.OpcodeVecI8x16Splat,
- wasm.OpcodeVecI16x8Splat,
- wasm.OpcodeVecI32x4Splat:
- return signature_I32_V128, nil
- case wasm.OpcodeVecI64x2Splat:
- return signature_I64_V128, nil
- case wasm.OpcodeVecF32x4Splat:
- return signature_F32_V128, nil
- case wasm.OpcodeVecF64x2Splat:
- return signature_F64_V128, nil
- case wasm.OpcodeVecV128i8x16Shuffle, wasm.OpcodeVecI8x16Swizzle, wasm.OpcodeVecV128And, wasm.OpcodeVecV128Or, wasm.OpcodeVecV128Xor, wasm.OpcodeVecV128AndNot:
- return signature_V128V128_V128, nil
- case wasm.OpcodeVecI8x16AllTrue, wasm.OpcodeVecI16x8AllTrue, wasm.OpcodeVecI32x4AllTrue, wasm.OpcodeVecI64x2AllTrue,
- wasm.OpcodeVecV128AnyTrue,
- wasm.OpcodeVecI8x16BitMask, wasm.OpcodeVecI16x8BitMask, wasm.OpcodeVecI32x4BitMask, wasm.OpcodeVecI64x2BitMask:
- return signature_V128_I32, nil
- case wasm.OpcodeVecV128Not, wasm.OpcodeVecI8x16Neg, wasm.OpcodeVecI16x8Neg, wasm.OpcodeVecI32x4Neg, wasm.OpcodeVecI64x2Neg,
- wasm.OpcodeVecF32x4Neg, wasm.OpcodeVecF64x2Neg, wasm.OpcodeVecF32x4Sqrt, wasm.OpcodeVecF64x2Sqrt,
- wasm.OpcodeVecI8x16Abs, wasm.OpcodeVecI8x16Popcnt, wasm.OpcodeVecI16x8Abs, wasm.OpcodeVecI32x4Abs, wasm.OpcodeVecI64x2Abs,
- wasm.OpcodeVecF32x4Abs, wasm.OpcodeVecF64x2Abs,
- wasm.OpcodeVecF32x4Ceil, wasm.OpcodeVecF32x4Floor, wasm.OpcodeVecF32x4Trunc, wasm.OpcodeVecF32x4Nearest,
- wasm.OpcodeVecF64x2Ceil, wasm.OpcodeVecF64x2Floor, wasm.OpcodeVecF64x2Trunc, wasm.OpcodeVecF64x2Nearest,
- wasm.OpcodeVecI16x8ExtendLowI8x16S, wasm.OpcodeVecI16x8ExtendHighI8x16S, wasm.OpcodeVecI16x8ExtendLowI8x16U, wasm.OpcodeVecI16x8ExtendHighI8x16U,
- wasm.OpcodeVecI32x4ExtendLowI16x8S, wasm.OpcodeVecI32x4ExtendHighI16x8S, wasm.OpcodeVecI32x4ExtendLowI16x8U, wasm.OpcodeVecI32x4ExtendHighI16x8U,
- wasm.OpcodeVecI64x2ExtendLowI32x4S, wasm.OpcodeVecI64x2ExtendHighI32x4S, wasm.OpcodeVecI64x2ExtendLowI32x4U, wasm.OpcodeVecI64x2ExtendHighI32x4U,
- wasm.OpcodeVecI16x8ExtaddPairwiseI8x16S, wasm.OpcodeVecI16x8ExtaddPairwiseI8x16U, wasm.OpcodeVecI32x4ExtaddPairwiseI16x8S, wasm.OpcodeVecI32x4ExtaddPairwiseI16x8U,
- wasm.OpcodeVecF64x2PromoteLowF32x4Zero, wasm.OpcodeVecF32x4DemoteF64x2Zero,
- wasm.OpcodeVecF32x4ConvertI32x4S, wasm.OpcodeVecF32x4ConvertI32x4U,
- wasm.OpcodeVecF64x2ConvertLowI32x4S, wasm.OpcodeVecF64x2ConvertLowI32x4U,
- wasm.OpcodeVecI32x4TruncSatF32x4S, wasm.OpcodeVecI32x4TruncSatF32x4U,
- wasm.OpcodeVecI32x4TruncSatF64x2SZero, wasm.OpcodeVecI32x4TruncSatF64x2UZero:
- return signature_V128_V128, nil
- case wasm.OpcodeVecV128Bitselect:
- return signature_V128V128V128_V32, nil
- case wasm.OpcodeVecI8x16Eq, wasm.OpcodeVecI8x16Ne, wasm.OpcodeVecI8x16LtS, wasm.OpcodeVecI8x16LtU, wasm.OpcodeVecI8x16GtS,
- wasm.OpcodeVecI8x16GtU, wasm.OpcodeVecI8x16LeS, wasm.OpcodeVecI8x16LeU, wasm.OpcodeVecI8x16GeS, wasm.OpcodeVecI8x16GeU,
- wasm.OpcodeVecI16x8Eq, wasm.OpcodeVecI16x8Ne, wasm.OpcodeVecI16x8LtS, wasm.OpcodeVecI16x8LtU, wasm.OpcodeVecI16x8GtS,
- wasm.OpcodeVecI16x8GtU, wasm.OpcodeVecI16x8LeS, wasm.OpcodeVecI16x8LeU, wasm.OpcodeVecI16x8GeS, wasm.OpcodeVecI16x8GeU,
- wasm.OpcodeVecI32x4Eq, wasm.OpcodeVecI32x4Ne, wasm.OpcodeVecI32x4LtS, wasm.OpcodeVecI32x4LtU, wasm.OpcodeVecI32x4GtS,
- wasm.OpcodeVecI32x4GtU, wasm.OpcodeVecI32x4LeS, wasm.OpcodeVecI32x4LeU, wasm.OpcodeVecI32x4GeS, wasm.OpcodeVecI32x4GeU,
- wasm.OpcodeVecI64x2Eq, wasm.OpcodeVecI64x2Ne, wasm.OpcodeVecI64x2LtS, wasm.OpcodeVecI64x2GtS, wasm.OpcodeVecI64x2LeS,
- wasm.OpcodeVecI64x2GeS, wasm.OpcodeVecF32x4Eq, wasm.OpcodeVecF32x4Ne, wasm.OpcodeVecF32x4Lt, wasm.OpcodeVecF32x4Gt,
- wasm.OpcodeVecF32x4Le, wasm.OpcodeVecF32x4Ge, wasm.OpcodeVecF64x2Eq, wasm.OpcodeVecF64x2Ne, wasm.OpcodeVecF64x2Lt,
- wasm.OpcodeVecF64x2Gt, wasm.OpcodeVecF64x2Le, wasm.OpcodeVecF64x2Ge,
- wasm.OpcodeVecI8x16Add, wasm.OpcodeVecI8x16AddSatS, wasm.OpcodeVecI8x16AddSatU, wasm.OpcodeVecI8x16Sub,
- wasm.OpcodeVecI8x16SubSatS, wasm.OpcodeVecI8x16SubSatU,
- wasm.OpcodeVecI16x8Add, wasm.OpcodeVecI16x8AddSatS, wasm.OpcodeVecI16x8AddSatU, wasm.OpcodeVecI16x8Sub,
- wasm.OpcodeVecI16x8SubSatS, wasm.OpcodeVecI16x8SubSatU, wasm.OpcodeVecI16x8Mul,
- wasm.OpcodeVecI32x4Add, wasm.OpcodeVecI32x4Sub, wasm.OpcodeVecI32x4Mul,
- wasm.OpcodeVecI64x2Add, wasm.OpcodeVecI64x2Sub, wasm.OpcodeVecI64x2Mul,
- wasm.OpcodeVecF32x4Add, wasm.OpcodeVecF32x4Sub, wasm.OpcodeVecF32x4Mul, wasm.OpcodeVecF32x4Div,
- wasm.OpcodeVecF64x2Add, wasm.OpcodeVecF64x2Sub, wasm.OpcodeVecF64x2Mul, wasm.OpcodeVecF64x2Div,
- wasm.OpcodeVecI8x16MinS, wasm.OpcodeVecI8x16MinU, wasm.OpcodeVecI8x16MaxS, wasm.OpcodeVecI8x16MaxU, wasm.OpcodeVecI8x16AvgrU,
- wasm.OpcodeVecI16x8MinS, wasm.OpcodeVecI16x8MinU, wasm.OpcodeVecI16x8MaxS, wasm.OpcodeVecI16x8MaxU, wasm.OpcodeVecI16x8AvgrU,
- wasm.OpcodeVecI32x4MinS, wasm.OpcodeVecI32x4MinU, wasm.OpcodeVecI32x4MaxS, wasm.OpcodeVecI32x4MaxU,
- wasm.OpcodeVecF32x4Min, wasm.OpcodeVecF32x4Max, wasm.OpcodeVecF64x2Min, wasm.OpcodeVecF64x2Max,
- wasm.OpcodeVecF32x4Pmin, wasm.OpcodeVecF32x4Pmax, wasm.OpcodeVecF64x2Pmin, wasm.OpcodeVecF64x2Pmax,
- wasm.OpcodeVecI16x8Q15mulrSatS,
- wasm.OpcodeVecI16x8ExtMulLowI8x16S, wasm.OpcodeVecI16x8ExtMulHighI8x16S, wasm.OpcodeVecI16x8ExtMulLowI8x16U, wasm.OpcodeVecI16x8ExtMulHighI8x16U,
- wasm.OpcodeVecI32x4ExtMulLowI16x8S, wasm.OpcodeVecI32x4ExtMulHighI16x8S, wasm.OpcodeVecI32x4ExtMulLowI16x8U, wasm.OpcodeVecI32x4ExtMulHighI16x8U,
- wasm.OpcodeVecI64x2ExtMulLowI32x4S, wasm.OpcodeVecI64x2ExtMulHighI32x4S, wasm.OpcodeVecI64x2ExtMulLowI32x4U, wasm.OpcodeVecI64x2ExtMulHighI32x4U,
- wasm.OpcodeVecI32x4DotI16x8S,
- wasm.OpcodeVecI8x16NarrowI16x8S, wasm.OpcodeVecI8x16NarrowI16x8U, wasm.OpcodeVecI16x8NarrowI32x4S, wasm.OpcodeVecI16x8NarrowI32x4U:
- return signature_V128V128_V128, nil
- default:
- return nil, fmt.Errorf("unsupported vector instruction in interpreterir: %s", wasm.VectorInstructionName(vecOp))
- }
- case wasm.OpcodeAtomicPrefix:
- switch atomicOp := c.body[c.pc+1]; atomicOp {
- case wasm.OpcodeAtomicMemoryNotify:
- return signature_I32I32_I32, nil
- case wasm.OpcodeAtomicMemoryWait32:
- return signature_I32I32I64_I32, nil
- case wasm.OpcodeAtomicMemoryWait64:
- return signature_I32I64I64_I32, nil
- case wasm.OpcodeAtomicFence:
- return signature_None_None, nil
- case wasm.OpcodeAtomicI32Load, wasm.OpcodeAtomicI32Load8U, wasm.OpcodeAtomicI32Load16U:
- return signature_I32_I32, nil
- case wasm.OpcodeAtomicI64Load, wasm.OpcodeAtomicI64Load8U, wasm.OpcodeAtomicI64Load16U, wasm.OpcodeAtomicI64Load32U:
- return signature_I32_I64, nil
- case wasm.OpcodeAtomicI32Store, wasm.OpcodeAtomicI32Store8, wasm.OpcodeAtomicI32Store16:
- return signature_I32I32_None, nil
- case wasm.OpcodeAtomicI64Store, wasm.OpcodeAtomicI64Store8, wasm.OpcodeAtomicI64Store16, wasm.OpcodeAtomicI64Store32:
- return signature_I32I64_None, nil
- case wasm.OpcodeAtomicI32RmwAdd, wasm.OpcodeAtomicI32RmwSub, wasm.OpcodeAtomicI32RmwAnd, wasm.OpcodeAtomicI32RmwOr, wasm.OpcodeAtomicI32RmwXor, wasm.OpcodeAtomicI32RmwXchg,
- wasm.OpcodeAtomicI32Rmw8AddU, wasm.OpcodeAtomicI32Rmw8SubU, wasm.OpcodeAtomicI32Rmw8AndU, wasm.OpcodeAtomicI32Rmw8OrU, wasm.OpcodeAtomicI32Rmw8XorU, wasm.OpcodeAtomicI32Rmw8XchgU,
- wasm.OpcodeAtomicI32Rmw16AddU, wasm.OpcodeAtomicI32Rmw16SubU, wasm.OpcodeAtomicI32Rmw16AndU, wasm.OpcodeAtomicI32Rmw16OrU, wasm.OpcodeAtomicI32Rmw16XorU, wasm.OpcodeAtomicI32Rmw16XchgU:
- return signature_I32I32_I32, nil
- case wasm.OpcodeAtomicI64RmwAdd, wasm.OpcodeAtomicI64RmwSub, wasm.OpcodeAtomicI64RmwAnd, wasm.OpcodeAtomicI64RmwOr, wasm.OpcodeAtomicI64RmwXor, wasm.OpcodeAtomicI64RmwXchg,
- wasm.OpcodeAtomicI64Rmw8AddU, wasm.OpcodeAtomicI64Rmw8SubU, wasm.OpcodeAtomicI64Rmw8AndU, wasm.OpcodeAtomicI64Rmw8OrU, wasm.OpcodeAtomicI64Rmw8XorU, wasm.OpcodeAtomicI64Rmw8XchgU,
- wasm.OpcodeAtomicI64Rmw16AddU, wasm.OpcodeAtomicI64Rmw16SubU, wasm.OpcodeAtomicI64Rmw16AndU, wasm.OpcodeAtomicI64Rmw16OrU, wasm.OpcodeAtomicI64Rmw16XorU, wasm.OpcodeAtomicI64Rmw16XchgU,
- wasm.OpcodeAtomicI64Rmw32AddU, wasm.OpcodeAtomicI64Rmw32SubU, wasm.OpcodeAtomicI64Rmw32AndU, wasm.OpcodeAtomicI64Rmw32OrU, wasm.OpcodeAtomicI64Rmw32XorU, wasm.OpcodeAtomicI64Rmw32XchgU:
- return signature_I32I64_I64, nil
- case wasm.OpcodeAtomicI32RmwCmpxchg, wasm.OpcodeAtomicI32Rmw8CmpxchgU, wasm.OpcodeAtomicI32Rmw16CmpxchgU:
- return signature_I32I32I32_I32, nil
- case wasm.OpcodeAtomicI64RmwCmpxchg, wasm.OpcodeAtomicI64Rmw8CmpxchgU, wasm.OpcodeAtomicI64Rmw16CmpxchgU, wasm.OpcodeAtomicI64Rmw32CmpxchgU:
- return signature_I32I64I64_I64, nil
- default:
- return nil, fmt.Errorf("unsupported atomic instruction in interpreterir: %s", wasm.AtomicInstructionName(atomicOp))
- }
- default:
- return nil, fmt.Errorf("unsupported instruction in interpreterir: 0x%x", op)
- }
-}
-
-// funcTypeToIRSignatures is the central cache for a module to get the *signature
-// for function calls.
-type funcTypeToIRSignatures struct {
- directCalls []*signature
- indirectCalls []*signature
- wasmTypes []wasm.FunctionType
-}
-
-// get returns the *signature for the direct or indirect function call against functions whose type is at `typeIndex`.
-func (f *funcTypeToIRSignatures) get(typeIndex wasm.Index, indirect bool) *signature {
- var sig *signature
- if indirect {
- sig = f.indirectCalls[typeIndex]
- } else {
- sig = f.directCalls[typeIndex]
- }
- if sig != nil {
- return sig
- }
-
- tp := &f.wasmTypes[typeIndex]
- if indirect {
- sig = &signature{
- in: make([]unsignedType, 0, len(tp.Params)+1), // +1 to reserve space for call indirect index.
- out: make([]unsignedType, 0, len(tp.Results)),
- }
- } else {
- sig = &signature{
- in: make([]unsignedType, 0, len(tp.Params)),
- out: make([]unsignedType, 0, len(tp.Results)),
- }
- }
-
- for _, vt := range tp.Params {
- sig.in = append(sig.in, wasmValueTypeTounsignedType(vt))
- }
- for _, vt := range tp.Results {
- sig.out = append(sig.out, wasmValueTypeTounsignedType(vt))
- }
-
- if indirect {
- sig.in = append(sig.in, unsignedTypeI32)
- f.indirectCalls[typeIndex] = sig
- } else {
- f.directCalls[typeIndex] = sig
- }
- return sig
-}
-
-func wasmValueTypeTounsignedType(vt wasm.ValueType) unsignedType {
- switch vt {
- case wasm.ValueTypeI32:
- return unsignedTypeI32
- case wasm.ValueTypeI64,
- // From interpreterir layer, ref type values are opaque 64-bit pointers.
- wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
- return unsignedTypeI64
- case wasm.ValueTypeF32:
- return unsignedTypeF32
- case wasm.ValueTypeF64:
- return unsignedTypeF64
- case wasm.ValueTypeV128:
- return unsignedTypeV128
- }
- panic("unreachable")
-}
-
-func wasmValueTypeToUnsignedOutSignature(vt wasm.ValueType) *signature {
- switch vt {
- case wasm.ValueTypeI32:
- return signature_None_I32
- case wasm.ValueTypeI64,
- // From interpreterir layer, ref type values are opaque 64-bit pointers.
- wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
- return signature_None_I64
- case wasm.ValueTypeF32:
- return signature_None_F32
- case wasm.ValueTypeF64:
- return signature_None_F64
- case wasm.ValueTypeV128:
- return signature_None_V128
- }
- panic("unreachable")
-}
-
-func wasmValueTypeToUnsignedInSignature(vt wasm.ValueType) *signature {
- switch vt {
- case wasm.ValueTypeI32:
- return signature_I32_None
- case wasm.ValueTypeI64,
- // From interpreterir layer, ref type values are opaque 64-bit pointers.
- wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
- return signature_I64_None
- case wasm.ValueTypeF32:
- return signature_F32_None
- case wasm.ValueTypeF64:
- return signature_F64_None
- case wasm.ValueTypeV128:
- return signature_V128_None
- }
- panic("unreachable")
-}
-
-func wasmValueTypeToUnsignedInOutSignature(vt wasm.ValueType) *signature {
- switch vt {
- case wasm.ValueTypeI32:
- return signature_I32_I32
- case wasm.ValueTypeI64,
- // At interpreterir layer, ref type values are opaque 64-bit pointers.
- wasm.ValueTypeExternref, wasm.ValueTypeFuncref:
- return signature_I64_I64
- case wasm.ValueTypeF32:
- return signature_F32_F32
- case wasm.ValueTypeF64:
- return signature_F64_F64
- case wasm.ValueTypeV128:
- return signature_V128_V128
- }
- panic("unreachable")
-}