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-14 20:54:53 -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.err = fmt.Errorf("Instruction limit (%d) exceeded", state.program.InstructionLimit)
|
|
|
|
|
state.running = false
|
|
|
|
|
}
|
2021-11-18 17:53:38 -10:00
|
|
|
|
2021-11-20 19:17:35 -10:00
|
|
|
if state.functionIndex < 0 || state.functionIndex >= int64(len(state.program.Functions)) {
|
2021-11-19 15:45:51 -10:00
|
|
|
state.ret()
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-20 19:17:35 -10:00
|
|
|
if state.instructionIndex < 0 || state.instructionIndex >= int64(len(fnc.Instructions)) {
|
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 20:54:53 -10:00
|
|
|
|
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-14 20:54:53 -10:00
|
|
|
}
|
2021-11-16 16:21:32 -10:00
|
|
|
return value
|
2021-11-14 20:54:53 -10:00
|
|
|
|
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-14 20:54:53 -10:00
|
|
|
}
|
2021-11-16 16:15:46 -10:00
|
|
|
return value
|
2021-11-14 20:54:53 -10:00
|
|
|
|
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 20:54:53 -10:00
|
|
|
|
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 20:54:53 -10:00
|
|
|
}
|
|
|
|
|
|
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 20:54:53 -10:00
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2021-11-14 20:54:53 -10: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
|
|
|
|
|
}
|