mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-01-14 07:57:57 -05:00
Reorganize using workspaces
This commit is contained in:
439
valuescript_vm/src/bytecode_stack_frame.rs
Normal file
439
valuescript_vm/src/bytecode_stack_frame.rs
Normal file
@@ -0,0 +1,439 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::vs_value::{Val, ValTrait, LoadFunctionResult};
|
||||
use super::vs_object::VsObject;
|
||||
use super::operations;
|
||||
use super::bytecode_decoder::BytecodeDecoder;
|
||||
use super::bytecode_decoder::BytecodeType;
|
||||
use super::instruction::Instruction;
|
||||
use super::stack_frame::{StackFrame, StackFrameTrait, FrameStepResult, CallResult};
|
||||
|
||||
pub struct BytecodeStackFrame {
|
||||
pub decoder: BytecodeDecoder,
|
||||
pub registers: Vec<Val>,
|
||||
pub param_start: usize,
|
||||
pub param_end: usize,
|
||||
pub this_target: Option<usize>,
|
||||
pub return_target: Option<usize>,
|
||||
}
|
||||
|
||||
impl BytecodeStackFrame {
|
||||
pub fn apply_unary_op(
|
||||
&mut self,
|
||||
op: fn(input: Val) -> Val,
|
||||
) {
|
||||
let input = self.decoder.decode_val(&self.registers);
|
||||
|
||||
let register_index = self.decoder.decode_register_index();
|
||||
|
||||
if register_index.is_some() {
|
||||
self.registers[register_index.unwrap()] = op(input);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn apply_binary_op(
|
||||
&mut self,
|
||||
op: fn(left: Val, right: Val) -> Val,
|
||||
) {
|
||||
let left = self.decoder.decode_val(&self.registers);
|
||||
let right = self.decoder.decode_val(&self.registers);
|
||||
|
||||
let register_index = self.decoder.decode_register_index();
|
||||
|
||||
if register_index.is_some() {
|
||||
self.registers[register_index.unwrap()] = op(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transfer_parameters(
|
||||
&mut self,
|
||||
new_frame: &mut StackFrame,
|
||||
) {
|
||||
let bytecode_type = self.decoder.decode_type();
|
||||
|
||||
if bytecode_type != BytecodeType::Array {
|
||||
std::panic!("Not implemented: call instruction not using inline array");
|
||||
}
|
||||
|
||||
while self.decoder.peek_type() != BytecodeType::End {
|
||||
let p = self.decoder.decode_val(&self.registers);
|
||||
new_frame.write_param(p);
|
||||
}
|
||||
|
||||
self.decoder.decode_type(); // End (TODO: assert)
|
||||
}
|
||||
|
||||
pub fn decode_parameters(
|
||||
&mut self,
|
||||
) -> Vec<Val> {
|
||||
let mut res = Vec::<Val>::new();
|
||||
|
||||
let bytecode_type = self.decoder.decode_type();
|
||||
|
||||
if bytecode_type != BytecodeType::Array {
|
||||
std::panic!("Not implemented: call instruction not using inline array");
|
||||
}
|
||||
|
||||
while self.decoder.peek_type() != BytecodeType::End {
|
||||
res.push(self.decoder.decode_val(&self.registers));
|
||||
}
|
||||
|
||||
self.decoder.decode_type(); // End (TODO: assert)
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
impl StackFrameTrait for BytecodeStackFrame {
|
||||
fn write_this(&mut self, this: Val) {
|
||||
self.registers[1] = this;
|
||||
}
|
||||
|
||||
fn write_param(&mut self, param: Val) {
|
||||
if self.param_start < self.param_end {
|
||||
self.registers[self.param_start] = param;
|
||||
self.param_start += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn step(&mut self) -> FrameStepResult {
|
||||
use Instruction::*;
|
||||
|
||||
match self.decoder.decode_instruction() {
|
||||
End => {
|
||||
return FrameStepResult::Pop(CallResult {
|
||||
return_: self.registers[0].clone(),
|
||||
this: self.registers[1].clone(),
|
||||
});
|
||||
},
|
||||
|
||||
Mov => {
|
||||
let val = self.decoder.decode_val(&self.registers);
|
||||
let register_index = self.decoder.decode_register_index();
|
||||
|
||||
if register_index.is_some() {
|
||||
self.registers[register_index.unwrap()] = val;
|
||||
}
|
||||
},
|
||||
|
||||
OpInc => {
|
||||
let register_index = self.decoder.decode_register_index().unwrap();
|
||||
let mut val = self.registers[register_index].clone();
|
||||
val = operations::op_plus(val, Val::Number(1_f64));
|
||||
self.registers[register_index] = val;
|
||||
},
|
||||
|
||||
OpDec => {
|
||||
let register_index = self.decoder.decode_register_index().unwrap();
|
||||
let mut val = self.registers[register_index].clone();
|
||||
val = operations::op_minus(val, Val::Number(1_f64));
|
||||
self.registers[register_index] = val;
|
||||
},
|
||||
|
||||
OpPlus => self.apply_binary_op(operations::op_plus),
|
||||
OpMinus => self.apply_binary_op(operations::op_minus),
|
||||
OpMul => self.apply_binary_op(operations::op_mul),
|
||||
OpDiv => self.apply_binary_op(operations::op_div),
|
||||
OpMod => self.apply_binary_op(operations::op_mod),
|
||||
OpExp => self.apply_binary_op(operations::op_exp),
|
||||
OpEq => self.apply_binary_op(operations::op_eq),
|
||||
OpNe => self.apply_binary_op(operations::op_ne),
|
||||
OpTripleEq => self.apply_binary_op(operations::op_triple_eq),
|
||||
OpTripleNe => self.apply_binary_op(operations::op_triple_ne),
|
||||
OpAnd => self.apply_binary_op(operations::op_and),
|
||||
OpOr => self.apply_binary_op(operations::op_or),
|
||||
|
||||
OpNot => self.apply_unary_op(operations::op_not),
|
||||
|
||||
OpLess => self.apply_binary_op(operations::op_less),
|
||||
OpLessEq => self.apply_binary_op(operations::op_less_eq),
|
||||
OpGreater => self.apply_binary_op(operations::op_greater),
|
||||
OpGreaterEq => self.apply_binary_op(operations::op_greater_eq),
|
||||
OpNullishCoalesce => self.apply_binary_op(operations::op_nullish_coalesce),
|
||||
OpOptionalChain => self.apply_binary_op(operations::op_optional_chain),
|
||||
OpBitAnd => self.apply_binary_op(operations::op_bit_and),
|
||||
OpBitOr => self.apply_binary_op(operations::op_bit_or),
|
||||
|
||||
OpBitNot => self.apply_unary_op(operations::op_bit_not),
|
||||
|
||||
OpBitXor => self.apply_binary_op(operations::op_bit_xor),
|
||||
OpLeftShift => self.apply_binary_op(operations::op_left_shift),
|
||||
OpRightShift => self.apply_binary_op(operations::op_right_shift),
|
||||
OpRightShiftUnsigned => self.apply_binary_op(operations::op_right_shift_unsigned),
|
||||
|
||||
TypeOf => self.apply_unary_op(operations::op_typeof),
|
||||
|
||||
InstanceOf => self.apply_binary_op(operations::op_instance_of),
|
||||
In => self.apply_binary_op(operations::op_in),
|
||||
|
||||
Call => {
|
||||
let fn_ = self.decoder.decode_val(&self.registers);
|
||||
|
||||
match fn_.load_function() {
|
||||
LoadFunctionResult::NotAFunction =>
|
||||
std::panic!("Not implemented: throw exception (fn_ is not a function)")
|
||||
,
|
||||
LoadFunctionResult::StackFrame(mut new_frame) => {
|
||||
self.transfer_parameters(&mut new_frame);
|
||||
|
||||
self.return_target = self.decoder.decode_register_index();
|
||||
self.this_target = None;
|
||||
|
||||
return FrameStepResult::Push(new_frame);
|
||||
},
|
||||
LoadFunctionResult::NativeFunction(native_fn) => {
|
||||
let res = native_fn(
|
||||
&mut Val::Undefined,
|
||||
self.decode_parameters(),
|
||||
);
|
||||
|
||||
match self.decoder.decode_register_index() {
|
||||
Some(return_target) => {
|
||||
self.registers[return_target] = res;
|
||||
},
|
||||
None => {},
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Apply => {
|
||||
let fn_ = self.decoder.decode_val(&self.registers);
|
||||
|
||||
match fn_.load_function() {
|
||||
LoadFunctionResult::NotAFunction =>
|
||||
std::panic!("Not implemented: throw exception (fn_ is not a function)")
|
||||
,
|
||||
LoadFunctionResult::StackFrame(mut new_frame) => {
|
||||
if self.decoder.peek_type() == BytecodeType::Register {
|
||||
self.decoder.decode_type();
|
||||
let this_target = self.decoder.decode_register_index();
|
||||
self.this_target = this_target;
|
||||
|
||||
if this_target.is_some() {
|
||||
new_frame.write_this(self.registers[this_target.unwrap()].clone());
|
||||
}
|
||||
} else {
|
||||
self.this_target = None;
|
||||
new_frame.write_this(self.decoder.decode_val(&self.registers));
|
||||
}
|
||||
|
||||
self.transfer_parameters(&mut new_frame);
|
||||
|
||||
self.return_target = self.decoder.decode_register_index();
|
||||
|
||||
return FrameStepResult::Push(new_frame);
|
||||
},
|
||||
LoadFunctionResult::NativeFunction(_native_fn) => {
|
||||
std::panic!("Not implemented");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Bind => {
|
||||
let fn_val = self.decoder.decode_val(&self.registers);
|
||||
let params = self.decoder.decode_val(&self.registers);
|
||||
let register_index = self.decoder.decode_register_index();
|
||||
|
||||
let params_array = params.as_array_data();
|
||||
|
||||
if params_array.is_none() {
|
||||
// Not sure this needs to be an exception in future since compiled
|
||||
// code should never violate this
|
||||
std::panic!("bind params should always be array")
|
||||
}
|
||||
|
||||
let bound_fn = fn_val.bind((*params_array.unwrap()).elements.clone());
|
||||
|
||||
if bound_fn.is_none() {
|
||||
// Not sure this needs to be an exception in future since compiled
|
||||
// code should never violate this
|
||||
std::panic!("fn parameter of bind should always be bindable");
|
||||
}
|
||||
|
||||
if register_index.is_some() {
|
||||
self.registers[register_index.unwrap()] = bound_fn.unwrap();
|
||||
}
|
||||
},
|
||||
|
||||
Sub => self.apply_binary_op(operations::op_sub),
|
||||
|
||||
SubMov => {
|
||||
let subscript = self.decoder.decode_val(&self.registers);
|
||||
let value = self.decoder.decode_val(&self.registers);
|
||||
|
||||
let register_index = self.decoder.decode_register_index().unwrap();
|
||||
let mut target = self.registers[register_index].clone(); // TODO: Lift
|
||||
|
||||
operations::op_submov(&mut target, subscript, value);
|
||||
self.registers[register_index] = target;
|
||||
},
|
||||
|
||||
SubCall => {
|
||||
let mut obj = match self.decoder.peek_type() {
|
||||
BytecodeType::Register => {
|
||||
self.decoder.decode_type();
|
||||
|
||||
ThisArg::Register(
|
||||
self.decoder.decode_register_index().unwrap()
|
||||
)
|
||||
},
|
||||
_ => ThisArg::Val(self.decoder.decode_val(&self.registers)),
|
||||
};
|
||||
|
||||
let subscript = self.decoder.decode_val(&self.registers);
|
||||
|
||||
let fn_ = operations::op_sub(
|
||||
match &obj {
|
||||
ThisArg::Register(reg_i) => self.registers[reg_i.clone()].clone(),
|
||||
ThisArg::Val(val) => val.clone(),
|
||||
},
|
||||
subscript,
|
||||
);
|
||||
|
||||
match fn_.load_function() {
|
||||
LoadFunctionResult::NotAFunction =>
|
||||
std::panic!("Not implemented: throw exception (fn_ is not a function)")
|
||||
,
|
||||
LoadFunctionResult::StackFrame(mut new_frame) => {
|
||||
self.transfer_parameters(&mut new_frame);
|
||||
|
||||
new_frame.write_this(match &obj {
|
||||
ThisArg::Register(reg_i) => self.registers[reg_i.clone()].clone(),
|
||||
ThisArg::Val(val) => val.clone(),
|
||||
});
|
||||
|
||||
self.return_target = self.decoder.decode_register_index();
|
||||
|
||||
self.this_target = match obj {
|
||||
ThisArg::Register(reg_i) => Some(reg_i),
|
||||
ThisArg::Val(_) => None,
|
||||
};
|
||||
|
||||
return FrameStepResult::Push(new_frame);
|
||||
},
|
||||
LoadFunctionResult::NativeFunction(native_fn) => {
|
||||
let params = self.decode_parameters();
|
||||
|
||||
let res = match &mut obj {
|
||||
ThisArg::Register(reg_i) => {
|
||||
native_fn(
|
||||
self.registers.get_mut(reg_i.clone()).unwrap(),
|
||||
params,
|
||||
)
|
||||
},
|
||||
ThisArg::Val(val) => {
|
||||
native_fn(
|
||||
val,
|
||||
params,
|
||||
)
|
||||
},
|
||||
};
|
||||
|
||||
match self.decoder.decode_register_index() {
|
||||
Some(return_target) => {
|
||||
self.registers[return_target] = res;
|
||||
},
|
||||
None => {},
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
Jmp => {
|
||||
let dst = self.decoder.decode_pos();
|
||||
self.decoder.pos = dst;
|
||||
}
|
||||
|
||||
JmpIf => {
|
||||
let cond = self.decoder.decode_val(&self.registers);
|
||||
let dst = self.decoder.decode_pos();
|
||||
|
||||
if cond.is_truthy() {
|
||||
self.decoder.pos = dst;
|
||||
}
|
||||
}
|
||||
|
||||
UnaryPlus => self.apply_unary_op(operations::op_unary_plus),
|
||||
UnaryMinus => self.apply_unary_op(operations::op_unary_minus),
|
||||
|
||||
New => {
|
||||
let class = self.decoder.decode_val(&self.registers)
|
||||
.as_class_data()
|
||||
.expect("Not implemented: throw exception (not constructible)");
|
||||
|
||||
let mut instance = Val::Object(Rc::new(VsObject {
|
||||
string_map: Default::default(),
|
||||
prototype: Some(class.instance_prototype.clone()),
|
||||
}));
|
||||
|
||||
match class.constructor {
|
||||
Val::Void => {
|
||||
// Ignore parameters
|
||||
self.decoder.decode_val(&self.registers);
|
||||
let target_register = self.decoder.decode_register_index();
|
||||
|
||||
match target_register {
|
||||
None => {},
|
||||
Some(tr) => self.registers[tr] = instance,
|
||||
};
|
||||
},
|
||||
_ => match class.constructor.load_function() {
|
||||
LoadFunctionResult::NotAFunction =>
|
||||
std::panic!("Not implemented: throw exception (class.constructor is not a function)")
|
||||
,
|
||||
LoadFunctionResult::StackFrame(mut new_frame) => {
|
||||
self.transfer_parameters(&mut new_frame);
|
||||
new_frame.write_this(instance);
|
||||
|
||||
self.return_target = None;
|
||||
self.this_target = self.decoder.decode_register_index();
|
||||
|
||||
return FrameStepResult::Push(new_frame);
|
||||
},
|
||||
LoadFunctionResult::NativeFunction(native_fn) => {
|
||||
native_fn(
|
||||
&mut instance,
|
||||
self.decode_parameters(),
|
||||
);
|
||||
|
||||
match self.decoder.decode_register_index() {
|
||||
Some(target) => {
|
||||
self.registers[target] = instance;
|
||||
},
|
||||
None => {},
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
return FrameStepResult::Continue;
|
||||
}
|
||||
|
||||
fn apply_call_result(&mut self, call_result: CallResult) {
|
||||
match self.this_target {
|
||||
None => {},
|
||||
Some(tt) => {
|
||||
self.registers[tt] = call_result.this;
|
||||
},
|
||||
};
|
||||
|
||||
match self.return_target {
|
||||
None => {},
|
||||
Some(rt) => {
|
||||
self.registers[rt] = call_result.return_;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
fn get_call_result(&mut self) -> CallResult {
|
||||
std::panic!("Not appropriate for BytecodeStackFrame")
|
||||
}
|
||||
}
|
||||
|
||||
enum ThisArg {
|
||||
Register(usize),
|
||||
Val(Val),
|
||||
}
|
||||
Reference in New Issue
Block a user