Move vm into subdir
This commit is contained in:
165
vm/state.go
Normal file
165
vm/state.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package vm
|
||||
|
||||
import "fmt"
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
type State struct {
|
||||
running bool
|
||||
err error
|
||||
|
||||
functions [][]*Instruction
|
||||
functionIndex int64
|
||||
instructionIndex int64
|
||||
|
||||
comparisonResult bool
|
||||
globalMemory *memory
|
||||
stack []*stackFrame
|
||||
}
|
||||
|
||||
func NewState(functions [][]*Instruction) (*State, error) {
|
||||
return &State{
|
||||
functions: functions,
|
||||
globalMemory: newMemory(16),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewStateFromByteCode(byteCodes [][]byte) (*State, error) {
|
||||
functions := [][]*Instruction{}
|
||||
|
||||
for i, byteCode := range byteCodes {
|
||||
instrs, err := NewInstructionsFromByteCode(byteCode)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "At function index %d", i)
|
||||
}
|
||||
|
||||
functions = append(functions, instrs)
|
||||
}
|
||||
|
||||
return NewState(functions)
|
||||
}
|
||||
|
||||
func (state *State) Execute() {
|
||||
state.setHandlers()
|
||||
state.call(0)
|
||||
state.running = true
|
||||
|
||||
for state.running {
|
||||
state.processInstruction()
|
||||
}
|
||||
}
|
||||
|
||||
func (state *State) stackFrame() *stackFrame {
|
||||
return state.stack[len(state.stack)-1]
|
||||
}
|
||||
|
||||
func (state *State) function() []*Instruction {
|
||||
return state.functions[state.functionIndex]
|
||||
}
|
||||
|
||||
func (state *State) setError(err error) {
|
||||
state.err = err
|
||||
state.running = false
|
||||
}
|
||||
|
||||
func (state *State) setHandlers() {
|
||||
for _, fnc := range state.functions {
|
||||
for _, instr := range fnc {
|
||||
handler, found := opHandlers[instr.OpCode]
|
||||
if !found {
|
||||
state.setError(fmt.Errorf("Invalid OpCode: 0x%08x", instr.OpCode))
|
||||
return
|
||||
}
|
||||
|
||||
instr.opHandler = handler
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (state *State) processInstruction() {
|
||||
fnc := state.function()
|
||||
instr := fnc[state.instructionIndex]
|
||||
state.instructionIndex += 1
|
||||
instr.opHandler(state, instr)
|
||||
}
|
||||
|
||||
func (state *State) readUnsigned(op *Operand) uint64 {
|
||||
switch op.Type {
|
||||
case Literal:
|
||||
return op.Value
|
||||
|
||||
case FunctionMemoryIndex:
|
||||
value, err := state.stackFrame().functionMemory.readUnsigned(op.Value)
|
||||
if err != nil {
|
||||
state.setError(err)
|
||||
}
|
||||
return value
|
||||
|
||||
case GlobalMemoryIndex:
|
||||
value, err := state.globalMemory.readUnsigned(op.Value)
|
||||
if err != nil {
|
||||
state.setError(err)
|
||||
}
|
||||
return value
|
||||
|
||||
default:
|
||||
state.setError(fmt.Errorf("Unknown operand type: 0x%02x", op.Type))
|
||||
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:
|
||||
state.setError(fmt.Errorf("Write to literal operand"))
|
||||
|
||||
case FunctionMemoryIndex:
|
||||
err := state.stackFrame().functionMemory.writeUnsigned(op.Value, value)
|
||||
if err != nil {
|
||||
state.setError(err)
|
||||
}
|
||||
|
||||
case GlobalMemoryIndex:
|
||||
err := state.globalMemory.writeUnsigned(op.Value, value)
|
||||
if err != nil {
|
||||
state.setError(err)
|
||||
}
|
||||
|
||||
default:
|
||||
state.setError(fmt.Errorf("Unknown operand type: 0x%02x", op.Type))
|
||||
}
|
||||
}
|
||||
|
||||
func (state *State) writeSigned(op *Operand, value int64) {
|
||||
state.writeUnsigned(op, uint64(value))
|
||||
}
|
||||
|
||||
func (state *State) call(functionOffset int64) {
|
||||
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
|
||||
}
|
||||
|
||||
stackFrame := newStackFrame(state)
|
||||
state.stack = append(state.stack, stackFrame)
|
||||
state.functionIndex += functionOffset
|
||||
state.instructionIndex = 0
|
||||
}
|
||||
|
||||
func (state *State) ret() {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
func (state *State) jump(instructionOffset int64) {
|
||||
// -1 accounts for the +1 processInstruction()
|
||||
state.instructionIndex += instructionOffset - 1
|
||||
}
|
||||
Reference in New Issue
Block a user