Files
subcoding/state.go

171 lines
4.0 KiB
Go
Raw Normal View History

2021-11-15 20:36:02 -10:00
package vm
2021-11-14 16:27:03 -08:00
import "fmt"
import "github.com/pkg/errors"
2021-11-15 20:49:54 -10:00
const globalMemoryEntries = 16
2021-11-14 16:27:03 -08:00
type State struct {
2021-11-15 20:49:54 -10:00
running bool
err error
2021-11-14 16:27:03 -08:00
2021-11-15 20:49:54 -10:00
functions [][]*Instruction
functionIndex int64
instructionIndex int64
2021-11-14 16:27:03 -08:00
2021-11-15 20:49:54 -10:00
comparisonResult bool
globalMemory [globalMemoryEntries]uint64
stack []*StackFrame
2021-11-14 16:27:03 -08:00
}
2021-11-15 16:39:30 -10:00
func NewState(byteCodes [][]byte) (*State, error) {
state := &State{}
for i, byteCode := range byteCodes {
instrs := []*Instruction{}
for start := 0; start < len(byteCode); start += InstructionBytes {
chunk := byteCode[start : start+InstructionBytes]
instr, err := NewInstruction(chunk)
if err != nil {
return nil, errors.Wrapf(err, "At function index %d, byte offset %d", i, start)
}
instrs = append(instrs, instr)
}
2021-11-15 20:24:20 -10:00
instrs = append(instrs, &Instruction{
OpCode: OpReturn,
})
2021-11-15 20:49:54 -10:00
state.functions = append(state.functions, instrs)
2021-11-15 16:39:30 -10:00
}
return state, nil
2021-11-14 16:27:03 -08:00
}
func (state *State) StackFrame() *StackFrame {
2021-11-15 20:49:54 -10:00
return state.stack[len(state.stack)-1]
}
2021-11-15 16:39:30 -10:00
func (state *State) Function() []*Instruction {
2021-11-15 20:49:54 -10:00
return state.functions[state.functionIndex]
}
2021-11-14 16:27:03 -08:00
func (state *State) Execute() {
2021-11-15 20:24:20 -10:00
state.setHandlers()
2021-11-14 20:37:33 -10:00
state.call(0)
2021-11-15 20:49:54 -10:00
state.running = true
2021-11-14 20:37:33 -10:00
2021-11-15 20:49:54 -10:00
for state.running {
2021-11-15 16:39:30 -10:00
state.ProcessInstruction()
2021-11-15 16:46:37 -10:00
}
}
2021-11-15 20:24:20 -10:00
func (state *State) setError(err error) {
2021-11-15 20:49:54 -10:00
state.err = err
state.running = false
2021-11-15 20:24:20 -10:00
}
func (state *State) setHandlers() {
2021-11-15 20:49:54 -10:00
for _, fnc := range state.functions {
2021-11-15 16:46:37 -10:00
for _, instr := range fnc {
handler, found := OpHandlers[instr.OpCode]
if !found {
2021-11-15 20:24:20 -10:00
state.setError(fmt.Errorf("Invalid OpCode: 0x%08x", instr.OpCode))
2021-11-15 16:46:37 -10:00
return
}
2021-11-14 16:27:03 -08:00
2021-11-15 16:46:37 -10:00
instr.opHandler = handler
2021-11-15 16:39:30 -10:00
}
2021-11-14 16:27:03 -08:00
}
}
2021-11-15 16:39:30 -10:00
func (state *State) ProcessInstruction() {
fnc := state.Function()
2021-11-15 20:49:54 -10:00
instr := fnc[state.instructionIndex]
state.instructionIndex += 1
2021-11-15 16:46:37 -10:00
instr.opHandler(state, instr)
2021-11-14 16:27:03 -08:00
}
func (state *State) ReadUnsigned(op *Operand) uint64 {
switch op.Type {
case Literal:
return op.Value
2021-11-14 16:27:03 -08:00
case FunctionMemoryIndex:
if op.Value >= FunctionMemoryEntries {
2021-11-15 20:24:20 -10:00
state.setError(fmt.Errorf("Invalid function memory index: %016x", op.Value))
return 0
}
return state.StackFrame().FunctionMemory[op.Value]
2021-11-14 16:27:03 -08:00
case GlobalMemoryIndex:
2021-11-15 20:49:54 -10:00
if op.Value >= globalMemoryEntries {
2021-11-15 20:24:20 -10:00
state.setError(fmt.Errorf("Invalid global memory index: %016x", op.Value))
return 0
}
2021-11-15 20:49:54 -10:00
return state.globalMemory[op.Value]
2021-11-14 16:27:03 -08:00
default:
2021-11-15 20:24:20 -10:00
state.setError(fmt.Errorf("Unknown operand type: 0x%02x", op.Type))
2021-11-14 16:27:03 -08:00
return 0
}
}
func (state *State) ReadSigned(op *Operand) int64 {
return int64(state.ReadUnsigned(op))
}
func (state *State) WriteUnsigned(op *Operand, value uint64) {
switch op.Type {
case Literal:
2021-11-15 20:24:20 -10:00
state.setError(fmt.Errorf("Write to literal operand"))
2021-11-14 16:27:03 -08:00
case FunctionMemoryIndex:
if op.Value >= FunctionMemoryEntries {
2021-11-15 20:24:20 -10:00
state.setError(fmt.Errorf("Invalid function memory index: %016x", op.Value))
return
}
state.StackFrame().FunctionMemory[op.Value] = value
2021-11-14 16:27:03 -08:00
case GlobalMemoryIndex:
2021-11-15 20:49:54 -10:00
if op.Value >= globalMemoryEntries {
2021-11-15 20:24:20 -10:00
state.setError(fmt.Errorf("Invalid global memory index: %016x", op.Value))
return
}
2021-11-15 20:49:54 -10:00
state.globalMemory[op.Value] = value
2021-11-14 16:27:03 -08:00
default:
2021-11-15 20:24:20 -10:00
state.setError(fmt.Errorf("Unknown operand type: 0x%02x", op.Type))
2021-11-14 16:27:03 -08:00
}
}
func (state *State) WriteSigned(op *Operand, value int64) {
state.WriteUnsigned(op, uint64(value))
}
2021-11-14 20:37:33 -10:00
func (state *State) call(functionOffset int64) {
2021-11-15 20:49:54 -10:00
if state.functionIndex+functionOffset >= int64(len(state.functions)) {
state.setError(fmt.Errorf("Invalid function call index: %d + %d = %d", state.functionIndex, functionOffset, state.functionIndex+functionOffset))
return
}
2021-11-14 16:27:03 -08:00
stackFrame := &StackFrame{
2021-11-15 20:49:54 -10:00
PreviousFunctionIndex: state.functionIndex,
PreviousInstructionIndex: state.instructionIndex,
2021-11-14 16:27:03 -08:00
}
2021-11-15 20:49:54 -10:00
state.stack = append(state.stack, stackFrame)
state.functionIndex += functionOffset
state.instructionIndex = 0
2021-11-14 16:27:03 -08:00
}
func (state *State) ret() {
2021-11-15 20:49:54 -10:00
state.functionIndex = state.StackFrame().PreviousFunctionIndex
state.instructionIndex = state.StackFrame().PreviousInstructionIndex
state.stack = state.stack[:len(state.stack)-1]
if len(state.stack) == 0 {
state.running = false
2021-11-15 20:24:20 -10:00
}
2021-11-14 16:27:03 -08:00
}