Documentation ¶
Overview ¶
Package compile is used internally by wagon to convert standard structured WebAssembly bytecode into an unstructured form suitable for execution by it's VM. The conversion process consists of translating block instruction sequences and branch operators (br, br_if, br_table) to absolute jumps to PC values. For instance, an instruction sequence like:
loop i32.const 1 get_local 0 i32.add set_local 0 get_local 1 i32.const 1 i32.add tee_local 1 get_local 2 i32.eq br_if 0 end
Is "compiled" to:
i32.const 1 i32.add set_local 0 get_local 1 i32.const 1 i32.add tee_local 1 get_local 2 i32.eq jmpnz <addr> <preserve> <discard>
Where jmpnz is a jump-if-not-zero operator that takes certain arguments plus the jump address as immediates. This is in contrast with original WebAssembly bytecode, where the target of branch operators are relative block depths instead.
Index ¶
Constants ¶
const ( // APushWasmStack is a symbolic instruction representing the movement // of a value in an x86-64 register, to the top of the WASM stack. APushWasmStack = x86.ALAST + iota // APopWasmStack is a symbolic instruction representing the movement // of the top of the WASM stack, to a value in an x86-64 register. APopWasmStack // ALoadGlobalsSliceHeader is a symbolic instruction representing that // the slice header for wasm globals should be loaded into R15. This // allows us to defer instruction generation till later phases, so // this instruction can be a NOP if already loaded. ALoadGlobalsSliceHeader // ALoadLocalsFirstElem is a symbolic instruction representing that // the first wasm should be loaded into R15. This allows us to defer // instruction generation till later phases, so this instruction can // be a NOP if already loaded. ALoadLocalsFirstElem // AFlushStackLength is a symbolic instruction representing that // the WASM stack length should be flushed from registers to main memory, // if it is dirty. AFlushStackLength )
Variables ¶
var ( // OpJmp unconditionally jumps to the provided address. OpJmp byte = 0x0c // OpJmpZ jumps to the given address if the value at the top of the stack is zero. OpJmpZ byte = 0x03 // OpJmpNz jumps to the given address if the value at the top of the // stack is not zero. It also discards elements and optionally preserves // the topmost value on the stack OpJmpNz byte = 0x0d // OpDiscard discards a given number of elements from the execution stack. OpDiscard byte = 0x0b // OpDiscardPreserveTop discards a given number of elements from the // execution stack, while preserving the value on the top of the stack. OpDiscardPreserveTop byte = 0x05 )
Functions ¶
This section is empty.
Types ¶
type AMD64Backend ¶
type AMD64Backend struct { EmitBoundsChecks bool // contains filtered or unexported fields }
AMD64Backend is the native compiler backend for x86-64 architectures.
func (*AMD64Backend) Build ¶
func (b *AMD64Backend) Build(candidate CompilationCandidate, code []byte, meta *BytecodeMetadata) ([]byte, error)
Build implements exec.instructionBuilder.
func (*AMD64Backend) Scanner ¶
func (b *AMD64Backend) Scanner() *scanner
Scanner returns a scanner that can be used for emitting compilation candidates.
type BranchTable ¶
type BranchTable struct { Targets []Target // A list of targets, br_table pops an int value, and jumps to Targets[val] DefaultTarget Target // If val > len(Targets), the VM will jump here // contains filtered or unexported fields }
BranchTable is the structure pointed to by a rewritten br_table instruction. A rewritten br_table instruction is of the format:
br_table <table_index>
where <table_index> is the index to an array of BranchTable objects stored by the VM.
func CompileWithTable ¶
func CompileWithTable(disassembly []disasm.Instr) ([]byte, []*BranchTable)
Compile rewrites WebAssembly bytecode from its disassembly. TODO(vibhavp): Add options for optimizing code. Operators like i32.reinterpret/f32 are no-ops, and can be safely removed.
type BytecodeMetadata ¶
type BytecodeMetadata struct { BranchTables []*BranchTable Instructions []InstructionMetadata // Inbound jumps - used by the AOT/JIT scanner to // avoid generating native code which has an inbound // jump target somewhere deep inside. InboundTargets map[int64]struct{} }
BytecodeMetadata encapsulates metadata about a bytecode stream.
type CompilationCandidate ¶
type CompilationCandidate struct { Start uint // Bytecode index of the first opcode. End uint // Bytecode index of the last byte in the instruction. StartInstruction int // InstructionMeta index of the first instruction. EndInstruction int // InstructionMeta index of the last instruction. Metrics Metrics // Metrics about the instructions between first & last index. }
CompilationCandidate describes a range of bytecode that can be translated to native code.
func (*CompilationCandidate) Bounds ¶
func (s *CompilationCandidate) Bounds() (uint, uint)
Bounds returns the beginning & end index in the bytecode which this candidate would replace. The end index is not inclusive.
type CompletionStatus ¶
type CompletionStatus uint64
CompletionStatus describes the final status of a native execution.
const ( CompletionOK CompletionStatus = iota CompletionBadBounds CompletionUnreachable CompletionFatalInternalError CompletionDivideZero )
Valid completion statuses.
type InstructionMetadata ¶
type InstructionMetadata struct { Op byte // Start represents the byte offset of this instruction // in the function's instruction stream. Start int // Size is the number of bytes in the instruction stream // needed to represent this instruction. Size int }
InstructionMetadata describes a bytecode instruction.
type JITExitSignal ¶
type JITExitSignal uint64
JITExitSignal is the value returned from the execution of a native section. The bits of this packed 64bit value is encoded as follows: [00:04] Completion Status [04:08] Reserved [08:32] Index of the WASM instruction where the exit occurred. [32:64] Status-specific 32bit value.
func (JITExitSignal) CompletionStatus ¶
func (s JITExitSignal) CompletionStatus() CompletionStatus
CompletionStatus decodes and returns the completion status of the exit.
func (JITExitSignal) Index ¶
func (s JITExitSignal) Index() int
Index returns the index to the instruction where the exit happened. 0xffffff is returned if the exit was due to normal completion.
type MMapAllocator ¶
type MMapAllocator struct {
// contains filtered or unexported fields
}
MMapAllocator copies instructions into executable memory.
func (*MMapAllocator) AllocateExec ¶
func (a *MMapAllocator) AllocateExec(asm []byte) (NativeCodeUnit, error)
AllocateExec allocates a block of executable memory with the given code contained.
func (*MMapAllocator) Close ¶
func (a *MMapAllocator) Close() error
Close frees all pages allocated by the allocator.
type Metrics ¶
type Metrics struct {
MemoryReads, MemoryWrites uint
StackReads, StackWrites uint
AllOps int
IntegerOps int
FloatOps int
}
Metrics describes the heuristics of an instruction sequence.
type NativeCodeUnit ¶
type NativeCodeUnit interface {
Invoke(stack, locals, globals *[]uint64, mem *[]byte) JITExitSignal
}
NativeCodeUnit represents compiled native code.
type Target ¶
type Target struct { Addr int64 // The absolute address of the target Discard int64 // The number of elements to discard PreserveTop bool // Whether the top of the stack is to be preserved Return bool // Whether to return in order to take this branch/target }
Target is the "target" of a br_table instruction. Unlike other control instructions, br_table does jumps and discarding all by itself.