Files
subcoding/vm/state.go

165 lines
3.6 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"
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-19 20:16:01 -10:00
program *Program
2021-11-15 20:49:54 -10:00
functionIndex int64
instructionIndex int64
2021-11-14 16:27:03 -08:00
2021-11-15 20:49:54 -10:00
comparisonResult bool
2021-11-18 17:53:38 -10:00
globalMemory *Memory
2021-11-16 15:39:12 -10:00
stack []*stackFrame
2021-11-20 19:25:16 -10:00
instructionCount uint64
2021-11-14 16:27:03 -08:00
}
2021-11-19 20:16:01 -10:00
func NewState(prog *Program) (*State, error) {
2021-11-16 15:36:34 -10:00
return &State{
2021-11-19 20:16:01 -10:00
program: prog,
2021-11-20 18:27:06 -10:00
globalMemory: NewMemory(prog.GlobalMemorySize),
2021-11-16 15:36:34 -10:00
}, nil
}
2021-11-18 15:34:10 -10:00
func (state *State) Execute() error {
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-16 15:13:30 -10:00
state.processInstruction()
2021-11-15 16:46:37 -10:00
}
2021-11-18 15:34:10 -10:00
return state.err
2021-11-15 16:46:37 -10:00
}
2021-11-18 17:53:38 -10:00
func (state *State) GlobalMemory() *Memory {
return state.globalMemory
}
2021-11-16 15:39:12 -10:00
func (state *State) stackFrame() *stackFrame {
2021-11-16 15:13:30 -10:00
return state.stack[len(state.stack)-1]
}
2021-11-19 20:38:56 -10:00
func (state *State) function() *Function {
2021-11-19 20:16:01 -10:00
return state.program.Functions[state.functionIndex]
2021-11-16 15:13:30 -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-19 20:16:01 -10:00
for _, fnc := range state.program.Functions {
2021-11-19 20:38:56 -10:00
for _, instr := range fnc.Instructions {
2021-11-16 15:27:30 -10:00
handler, found := opHandlers[instr.OpCode]
2021-11-15 16:46:37 -10:00
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-16 15:13:30 -10:00
func (state *State) processInstruction() {
fnc := state.function()
2021-11-19 20:38:56 -10:00
instr := fnc.Instructions[state.instructionIndex]
2021-11-15 20:49:54 -10:00
state.instructionIndex += 1
2021-11-15 16:46:37 -10:00
instr.opHandler(state, instr)
2021-11-20 19:25:16 -10:00
state.instructionCount += 1
if state.program.InstructionLimit > 0 && state.instructionCount > state.program.InstructionLimit {
state.setError(fmt.Errorf("Instruction limit (%d) exceeded", state.program.InstructionLimit))
2021-11-20 19:25:16 -10:00
}
2021-11-18 17:53:38 -10:00
for state.functionIndex < 0 ||
state.functionIndex >= int64(len(state.program.Functions)) ||
state.instructionIndex < 0 ||
state.instructionIndex >= int64(len(state.function().Instructions)) {
2021-11-19 15:45:51 -10:00
2021-11-18 17:53:38 -10:00
state.ret()
}
2021-11-14 16:27:03 -08:00
}
2021-11-16 15:13:30 -10:00
func (state *State) readUnsigned(op *Operand) uint64 {
2021-11-14 16:27:03 -08:00
switch op.Type {
case Literal:
return op.Value
2021-11-14 16:27:03 -08:00
case FunctionMemoryIndex:
2021-11-18 17:53:38 -10:00
value, err := state.stackFrame().functionMemory.ReadUnsigned(op.Value)
2021-11-16 16:21:32 -10:00
if err != nil {
state.setError(err)
}
2021-11-16 16:21:32 -10:00
return value
2021-11-14 16:27:03 -08:00
case GlobalMemoryIndex:
2021-11-18 17:53:38 -10:00
value, err := state.globalMemory.ReadUnsigned(op.Value)
2021-11-16 16:15:46 -10:00
if err != nil {
state.setError(err)
}
2021-11-16 16:15:46 -10:00
return 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
}
}
2021-11-16 15:13:30 -10:00
func (state *State) readSigned(op *Operand) int64 {
return int64(state.readUnsigned(op))
2021-11-14 16:27:03 -08:00
}
2021-11-16 15:13:30 -10:00
func (state *State) writeUnsigned(op *Operand, value uint64) {
2021-11-14 16:27:03 -08:00
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:
2021-11-18 17:53:38 -10:00
err := state.stackFrame().functionMemory.WriteUnsigned(op.Value, value)
2021-11-16 16:21:32 -10:00
if err != nil {
state.setError(err)
}
2021-11-14 16:27:03 -08:00
case GlobalMemoryIndex:
2021-11-18 17:53:38 -10:00
err := state.globalMemory.WriteUnsigned(op.Value, value)
2021-11-16 16:15:46 -10:00
if err != nil {
state.setError(err)
}
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
}
}
2021-11-16 15:13:30 -10:00
func (state *State) writeSigned(op *Operand, value int64) {
state.writeUnsigned(op, uint64(value))
2021-11-14 16:27:03 -08:00
}
2021-11-14 20:37:33 -10:00
func (state *State) call(functionOffset int64) {
2021-11-16 16:21:32 -10:00
stackFrame := newStackFrame(state)
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-16 15:39:12 -10:00
state.functionIndex = state.stackFrame().previousFunctionIndex
state.instructionIndex = state.stackFrame().previousInstructionIndex
2021-11-15 20:49:54 -10:00
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
}
2021-11-16 15:33:03 -10:00
func (state *State) jump(instructionOffset int64) {
// -1 accounts for the +1 processInstruction()
state.instructionIndex += instructionOffset - 1
}