diff options
author | 2025-03-09 17:47:56 +0100 | |
---|---|---|
committer | 2025-03-10 01:59:49 +0100 | |
commit | 3ac1ee16f377d31a0fb80c8dae28b6239ac4229e (patch) | |
tree | f61faa581feaaeaba2542b9f2b8234a590684413 /vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/compiler.go | |
parent | [chore] update URLs to forked source (diff) | |
download | gotosocial-3ac1ee16f377d31a0fb80c8dae28b6239ac4229e.tar.xz |
[chore] remove vendor
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/compiler.go')
-rw-r--r-- | vendor/github.com/tetratelabs/wazero/internal/engine/interpreter/compiler.go | 3632 |
1 files changed, 0 insertions, 3632 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 -} |