215 lines
5.1 KiB
Go
215 lines
5.1 KiB
Go
// Copyright 2017 The go-interpreter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package exec
|
|
|
|
import (
|
|
"errors"
|
|
"math"
|
|
)
|
|
|
|
// ErrOutOfBoundsMemoryAccess is the error value used while trapping the VM
|
|
// when it detects an out of bounds access to the linear memory.
|
|
var ErrOutOfBoundsMemoryAccess = errors.New("exec: out of bounds memory access")
|
|
|
|
func (vm *VM) fetchBaseAddr() int {
|
|
return int(vm.fetchUint32() + uint32(vm.popInt32()))
|
|
}
|
|
|
|
// inBounds returns true when the next vm.fetchBaseAddr() + offset
|
|
// indices are in bounds accesses to the linear memory.
|
|
func (vm *VM) inBounds(offset int) bool {
|
|
addr := endianess.Uint32(vm.ctx.code[vm.ctx.pc:]) + uint32(vm.ctx.stack[len(vm.ctx.stack)-1])
|
|
return int(addr)+offset < len(vm.memory)
|
|
}
|
|
|
|
// curMem returns a slice to the memeory segment pointed to by
|
|
// the current base address on the bytecode stream.
|
|
func (vm *VM) curMem() []byte {
|
|
return vm.memory[vm.fetchBaseAddr():]
|
|
}
|
|
|
|
func (vm *VM) i32Load() {
|
|
if !vm.inBounds(3) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushUint32(endianess.Uint32(vm.curMem()))
|
|
}
|
|
|
|
func (vm *VM) i32Load8s() {
|
|
if !vm.inBounds(0) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushInt32(int32(int8(vm.memory[vm.fetchBaseAddr()])))
|
|
}
|
|
|
|
func (vm *VM) i32Load8u() {
|
|
if !vm.inBounds(0) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushUint32(uint32(uint8(vm.memory[vm.fetchBaseAddr()])))
|
|
}
|
|
|
|
func (vm *VM) i32Load16s() {
|
|
if !vm.inBounds(1) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushInt32(int32(int16(endianess.Uint16(vm.curMem()))))
|
|
}
|
|
|
|
func (vm *VM) i32Load16u() {
|
|
if !vm.inBounds(1) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushUint32(uint32(endianess.Uint16(vm.curMem())))
|
|
}
|
|
|
|
func (vm *VM) i64Load() {
|
|
if !vm.inBounds(7) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushUint64(endianess.Uint64(vm.curMem()))
|
|
}
|
|
|
|
func (vm *VM) i64Load8s() {
|
|
if !vm.inBounds(0) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushInt64(int64(int8(vm.memory[vm.fetchBaseAddr()])))
|
|
}
|
|
|
|
func (vm *VM) i64Load8u() {
|
|
if !vm.inBounds(0) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushUint64(uint64(uint8(vm.memory[vm.fetchBaseAddr()])))
|
|
}
|
|
|
|
func (vm *VM) i64Load16s() {
|
|
if !vm.inBounds(1) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushInt64(int64(int16(endianess.Uint16(vm.curMem()))))
|
|
}
|
|
|
|
func (vm *VM) i64Load16u() {
|
|
if !vm.inBounds(1) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushUint64(uint64(endianess.Uint16(vm.curMem())))
|
|
}
|
|
|
|
func (vm *VM) i64Load32s() {
|
|
if !vm.inBounds(3) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushInt64(int64(int32(endianess.Uint32(vm.curMem()))))
|
|
}
|
|
|
|
func (vm *VM) i64Load32u() {
|
|
if !vm.inBounds(3) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushUint64(uint64(endianess.Uint32(vm.curMem())))
|
|
}
|
|
|
|
func (vm *VM) f32Store() {
|
|
v := math.Float32bits(vm.popFloat32())
|
|
if !vm.inBounds(3) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
endianess.PutUint32(vm.curMem(), v)
|
|
}
|
|
|
|
func (vm *VM) f32Load() {
|
|
if !vm.inBounds(3) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushFloat32(math.Float32frombits(endianess.Uint32(vm.curMem())))
|
|
}
|
|
|
|
func (vm *VM) f64Store() {
|
|
v := math.Float64bits(vm.popFloat64())
|
|
if !vm.inBounds(7) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
endianess.PutUint64(vm.curMem(), v)
|
|
}
|
|
|
|
func (vm *VM) f64Load() {
|
|
if !vm.inBounds(7) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.pushFloat64(math.Float64frombits(endianess.Uint64(vm.curMem())))
|
|
}
|
|
|
|
func (vm *VM) i32Store() {
|
|
v := vm.popUint32()
|
|
if !vm.inBounds(3) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
endianess.PutUint32(vm.curMem(), v)
|
|
}
|
|
|
|
func (vm *VM) i32Store8() {
|
|
v := byte(uint8(vm.popUint32()))
|
|
if !vm.inBounds(0) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.memory[vm.fetchBaseAddr()] = v
|
|
}
|
|
|
|
func (vm *VM) i32Store16() {
|
|
v := uint16(vm.popUint32())
|
|
if !vm.inBounds(1) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
endianess.PutUint16(vm.curMem(), v)
|
|
}
|
|
|
|
func (vm *VM) i64Store() {
|
|
v := vm.popUint64()
|
|
if !vm.inBounds(7) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
endianess.PutUint64(vm.curMem(), v)
|
|
}
|
|
|
|
func (vm *VM) i64Store8() {
|
|
v := byte(uint8(vm.popUint64()))
|
|
if !vm.inBounds(0) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
vm.memory[vm.fetchBaseAddr()] = v
|
|
}
|
|
|
|
func (vm *VM) i64Store16() {
|
|
v := uint16(vm.popUint64())
|
|
if !vm.inBounds(1) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
endianess.PutUint16(vm.curMem(), v)
|
|
}
|
|
|
|
func (vm *VM) i64Store32() {
|
|
v := uint32(vm.popUint64())
|
|
if !vm.inBounds(3) {
|
|
panic(ErrOutOfBoundsMemoryAccess)
|
|
}
|
|
endianess.PutUint32(vm.curMem(), v)
|
|
}
|
|
|
|
func (vm *VM) currentMemory() {
|
|
_ = vm.fetchInt8() // reserved (https://github.com/WebAssembly/design/blob/27ac254c854994103c24834a994be16f74f54186/BinaryEncoding.md#memory-related-operators-described-here)
|
|
vm.pushInt32(int32(len(vm.memory) / wasmPageSize))
|
|
}
|
|
|
|
func (vm *VM) growMemory() {
|
|
_ = vm.fetchInt8() // reserved (https://github.com/WebAssembly/design/blob/27ac254c854994103c24834a994be16f74f54186/BinaryEncoding.md#memory-related-operators-described-here)
|
|
curLen := len(vm.memory) / wasmPageSize
|
|
n := vm.popInt32()
|
|
vm.memory = append(vm.memory, make([]byte, n*wasmPageSize)...)
|
|
vm.pushInt32(int32(curLen))
|
|
}
|