Lots of work e2e for reading/setting fields.

This commit is contained in:
Jesse Brault 2026-03-13 09:16:41 -05:00
parent 54e2a170a2
commit 8759c3be27
24 changed files with 828 additions and 347 deletions

View File

@ -10,7 +10,7 @@ use dmc_lib::symbol_table::SymbolTable;
use dmc_lib::token::TokenKind;
use dvm_lib::vm::constant::{Constant, StringConstant};
use dvm_lib::vm::function::Function;
use dvm_lib::vm::value::Value;
use dvm_lib::vm::operand::Operand;
use dvm_lib::vm::{CallStack, DvmContext, call};
use std::io;
use std::io::Write;
@ -76,7 +76,7 @@ pub fn repl(register_count: usize) {
);
}
let mut registers = vec![Value::Null; register_count];
let mut registers = vec![Operand::Null; register_count];
let mut call_stack = CallStack::new();
let result = call(&context, &mut registers, &mut call_stack, "__repl", &[]);

View File

@ -9,7 +9,7 @@ use dmc_lib::parser::parse_compilation_unit;
use dmc_lib::symbol_table::SymbolTable;
use dvm_lib::vm::constant::{Constant, StringConstant};
use dvm_lib::vm::function::Function;
use dvm_lib::vm::value::Value;
use dvm_lib::vm::operand::Operand;
use dvm_lib::vm::{CallStack, DvmContext, call};
use std::path::PathBuf;
@ -92,7 +92,7 @@ pub fn run(script: &PathBuf, show_ir: bool, show_asm: bool, register_count: usiz
);
}
let mut registers: Vec<Value> = vec![Value::Null; register_count];
let mut registers: Vec<Operand> = vec![Operand::Null; register_count];
let mut call_stack = CallStack::new();
let result = call(

View File

@ -7,6 +7,7 @@ use crate::ir::ir_allocate::IrAllocate;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_function::IrFunction;
use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_set_field::IrSetField;
@ -220,10 +221,40 @@ impl Constructor {
// next, initialize fields that have an initializer in their declaration
for field in fields {
if let Some(initializer) = field.initializer() {
// get a mut ref to the field
let ir_get_field_ref_mut = IrGetFieldRefMut::new(
self_variable.clone(),
field.field_symbol().borrow().field_index(),
);
let field_mut_ref_variable_name: Rc<str> = ir_builder.new_t_var().into();
let field_mut_ref_variable = Rc::new(RefCell::new(IrVariable::new_vr(
field_mut_ref_variable_name.clone(),
ir_builder.current_block().id(),
field.field_symbol().borrow().type_info(),
)));
let field_mut_ref_assign = IrAssign::new(
field_mut_ref_variable.clone(),
IrOperation::GetFieldRefMut(ir_get_field_ref_mut),
);
ir_builder
.current_block_mut()
.add_statement(IrStatement::Assign(field_mut_ref_assign));
// save the mut ref to the builder for other uses if needed
ir_builder
.field_mut_pointer_variables_mut()
.insert(field_mut_ref_variable_name.clone(), field_mut_ref_variable);
// now write the initializer result to the field
let field_mut_ref_variable = ir_builder
.field_mut_pointer_variables()
.get(&field_mut_ref_variable_name)
.unwrap()
.clone();
let ir_expression = initializer.to_ir(&mut ir_builder, symbol_table).unwrap();
let ir_set_field = IrSetField::new(
&self_variable.clone(),
field.field_symbol().borrow().field_index(),
&field_mut_ref_variable, // dumb that we clone it and then ref it
ir_expression,
);
ir_builder

View File

@ -13,6 +13,8 @@ pub struct IrBuilder {
blocks: HashMap<usize, Rc<RefCell<IrBlock>>>,
current_block_builder: Option<IrBlockBuilder>,
self_variable: Option<Rc<RefCell<IrVariable>>>,
field_variables: HashMap<Rc<str>, Rc<RefCell<IrVariable>>>,
mut_field_variables: HashMap<Rc<str>, Rc<RefCell<IrVariable>>>,
}
impl IrBuilder {
@ -24,6 +26,8 @@ impl IrBuilder {
blocks: HashMap::new(),
current_block_builder: None,
self_variable: None,
field_variables: HashMap::new(),
mut_field_variables: HashMap::new(),
}
}
@ -83,6 +87,26 @@ impl IrBuilder {
pub fn self_variable(&self) -> &Rc<RefCell<IrVariable>> {
self.self_variable.as_ref().unwrap()
}
pub fn field_pointer_variables(&self) -> &HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
&self.field_variables
}
pub fn field_pointer_variables_mut(
&mut self,
) -> &mut HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
&mut self.field_variables
}
pub fn field_mut_pointer_variables(&self) -> &HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
&self.mut_field_variables
}
pub fn field_mut_pointer_variables_mut(
&mut self,
) -> &mut HashMap<Rc<str>, Rc<RefCell<IrVariable>>> {
&mut self.mut_field_variables
}
}
pub struct IrBlockBuilder {

View File

@ -74,9 +74,6 @@ impl NegativeExpression {
.expect("Attempt to negate non-value expression");
match operand_as_ir {
IrExpression::Field(self_variable, _) => {
todo!()
}
IrExpression::Parameter(parameter) => {
let destination = Rc::new(RefCell::new(IrVariable::new_vr(
builder.new_t_var().into(),

View File

@ -3,7 +3,7 @@ use crate::ir::assemble::{Assemble, InstructionsBuilder};
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use dvm_lib::instruction::{Instruction, Location};
use dvm_lib::instruction::Instruction;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
@ -79,16 +79,41 @@ impl VrUser for IrAssign {
impl Assemble for IrAssign {
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
let destination = match self.destination.borrow().descriptor() {
IrVariableDescriptor::VirtualRegister(vr_variable) => {
Location::Register(vr_variable.assigned_register())
}
IrVariableDescriptor::Stack(stack_variable) => {
Location::StackFrameOffset(stack_variable.offset())
}
};
let destination = self.destination.borrow().descriptor().as_location();
match self.initializer.as_ref() {
IrOperation::GetFieldRef(ir_get_field_ref) => {
let self_location = ir_get_field_ref
.self_variable()
.borrow()
.descriptor()
.as_location();
builder.push(Instruction::GetFieldPointer(
self_location,
ir_get_field_ref.field_index(),
destination,
));
}
IrOperation::GetFieldRefMut(ir_get_field_ref) => {
let self_location = ir_get_field_ref
.self_variable()
.borrow()
.descriptor()
.as_location();
builder.push(Instruction::GetFieldPointerMut(
self_location,
ir_get_field_ref.field_index(),
destination,
));
}
IrOperation::ReadField(ir_read_field) => {
let field_ref_location = ir_read_field
.field_ref_variable()
.borrow()
.descriptor()
.as_location();
builder.push(Instruction::ReadField(field_ref_location, destination));
}
IrOperation::Load(ir_expression) => {
let move_operand = ir_expression.move_operand(constants_table);
builder.push(Instruction::Move(move_operand, destination));

View File

@ -1,5 +1,4 @@
use crate::constants_table::ConstantsTable;
use crate::ir::assemble::InstructionsBuilder;
use crate::ir::ir_parameter::IrParameter;
use crate::ir::ir_variable::{
IrStackVariableDescriptor, IrVariable, IrVariableDescriptor, IrVrVariableDescriptor,
@ -16,7 +15,6 @@ use std::fmt::{Display, Formatter};
use std::rc::Rc;
pub enum IrExpression {
Field(Rc<RefCell<IrVariable>>, usize),
Parameter(Rc<IrParameter>),
Variable(Rc<RefCell<IrVariable>>),
Int(i32),
@ -27,19 +25,6 @@ pub enum IrExpression {
impl IrExpression {
pub fn move_operand(&self, constants_table: &mut ConstantsTable) -> MoveOperand {
match self {
IrExpression::Field(self_variable, field_index) => {
match self_variable.borrow().descriptor() {
IrVariableDescriptor::VirtualRegister(register_self_variable) => {
MoveOperand::Location(Location::RegisterField(
register_self_variable.assigned_register(),
*field_index,
))
}
IrVariableDescriptor::Stack(stack_self_variable) => MoveOperand::Location(
Location::StackFrameOffsetField(stack_self_variable.offset(), *field_index),
),
}
}
IrExpression::Parameter(ir_parameter) => {
MoveOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
}
@ -62,9 +47,6 @@ impl IrExpression {
pub fn push_operand(&self, constants_table: &mut ConstantsTable) -> PushOperand {
match self {
IrExpression::Field(self_variable, _) => {
todo!()
}
IrExpression::Parameter(ir_parameter) => {
PushOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
}
@ -87,9 +69,6 @@ impl IrExpression {
pub fn add_operand(&self, constants_table: &mut ConstantsTable) -> AddOperand {
match self {
IrExpression::Field(self_variable, _) => {
todo!()
}
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
TypeInfo::Integer | TypeInfo::Double | TypeInfo::String => {
AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
@ -128,9 +107,6 @@ impl IrExpression {
pub fn subtract_operand(&self) -> SubtractOperand {
match self {
IrExpression::Field(self_variable, _) => {
todo!()
}
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
TypeInfo::Integer | TypeInfo::Double => SubtractOperand::Location(
Location::StackFrameOffset(ir_parameter.stack_offset()),
@ -166,9 +142,6 @@ impl IrExpression {
pub fn multiply_operand(&self) -> MultiplyOperand {
match self {
IrExpression::Field(self_variable, _) => {
todo!()
}
IrExpression::Parameter(ir_parameter) => {
MultiplyOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
}
@ -190,19 +163,6 @@ impl IrExpression {
pub fn return_operand(&self, constants_table: &mut ConstantsTable) -> ReturnOperand {
match self {
IrExpression::Field(self_variable, field_index) => {
match self_variable.borrow().descriptor() {
IrVariableDescriptor::VirtualRegister(self_register_variable) => {
ReturnOperand::Location(Location::RegisterField(
self_register_variable.assigned_register(),
*field_index,
))
}
IrVariableDescriptor::Stack(self_stack_variable) => ReturnOperand::Location(
Location::StackFrameOffsetField(self_stack_variable.offset(), *field_index),
),
}
}
IrExpression::Parameter(ir_parameter) => {
ReturnOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
}
@ -227,9 +187,6 @@ impl IrExpression {
pub fn set_field_operand(&self, constants_table: &mut ConstantsTable) -> SetFieldOperand {
match self {
IrExpression::Field(self_variable, _) => {
todo!()
}
IrExpression::Parameter(ir_parameter) => {
SetFieldOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
}
@ -254,9 +211,6 @@ impl IrExpression {
impl Display for IrExpression {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
IrExpression::Field(self_variable, field_index) => {
write!(f, "{}.{}", self_variable.borrow(), field_index)
}
IrExpression::Parameter(ir_parameter) => {
write!(f, "{}", ir_parameter)
}
@ -284,15 +238,6 @@ impl VrUser for IrExpression {
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
match self {
IrExpression::Field(self_variable, field_index) => {
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
self_variable.borrow().descriptor()
{
HashSet::from([vr_variable.clone()])
} else {
HashSet::new()
}
}
IrExpression::Parameter(_) => HashSet::new(),
IrExpression::Variable(ir_variable) => {
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
@ -311,9 +256,6 @@ impl VrUser for IrExpression {
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
match self {
IrExpression::Field(self_variable, field_index) => {
// no-op, no defs
}
IrExpression::Parameter(_) => {
// no-op
}
@ -350,9 +292,6 @@ impl VrUser for IrExpression {
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
match self {
IrExpression::Field(self_variable, field_index) => {
// no-op
}
IrExpression::Parameter(_) => {
// no-op
}

View File

@ -0,0 +1,59 @@
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
use std::rc::Rc;
pub struct IrGetFieldRef {
self_variable: Rc<RefCell<IrVariable>>,
field_index: usize,
}
impl IrGetFieldRef {
pub fn new(self_variable: Rc<RefCell<IrVariable>>, field_index: usize) -> Self {
Self {
self_variable,
field_index,
}
}
pub fn self_variable(&self) -> &Rc<RefCell<IrVariable>> {
&self.self_variable
}
pub fn field_index(&self) -> usize {
self.field_index
}
}
impl Display for IrGetFieldRef {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "&{}.{}", self.self_variable.borrow(), self.field_index)
}
}
impl VrUser for IrGetFieldRef {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
match self.self_variable.borrow().descriptor() {
IrVariableDescriptor::VirtualRegister(vr_variable) => {
HashSet::from([vr_variable.clone()])
}
IrVariableDescriptor::Stack(_) => HashSet::new(),
}
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
}
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {}
}

View File

@ -0,0 +1,64 @@
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
use std::rc::Rc;
pub struct IrGetFieldRefMut {
self_variable: Rc<RefCell<IrVariable>>,
field_index: usize,
}
impl IrGetFieldRefMut {
pub fn new(self_variable: Rc<RefCell<IrVariable>>, field_index: usize) -> Self {
Self {
self_variable,
field_index,
}
}
pub fn self_variable(&self) -> &Rc<RefCell<IrVariable>> {
&self.self_variable
}
pub fn field_index(&self) -> usize {
self.field_index
}
}
impl Display for IrGetFieldRefMut {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"&mut {}.{}",
self.self_variable.borrow(),
self.field_index()
)
}
}
impl VrUser for IrGetFieldRefMut {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
match self.self_variable.borrow().descriptor() {
IrVariableDescriptor::VirtualRegister(vr_variable) => {
HashSet::from([vr_variable.clone()])
}
IrVariableDescriptor::Stack(stack_variable) => HashSet::new(),
}
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
}
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {}
}

View File

@ -2,7 +2,10 @@ use crate::ir::ir_add::IrAdd;
use crate::ir::ir_allocate::IrAllocate;
use crate::ir::ir_call::IrCall;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_get_field_ref::IrGetFieldRef;
use crate::ir::ir_get_field_ref_mut::IrGetFieldRefMut;
use crate::ir::ir_multiply::IrMultiply;
use crate::ir::ir_read_field::IrReadField;
use crate::ir::ir_subtract::IrSubtract;
use crate::ir::ir_variable::IrVrVariableDescriptor;
use crate::ir::register_allocation::{OffsetCounter, VrUser};
@ -10,6 +13,9 @@ use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
pub enum IrOperation {
GetFieldRef(IrGetFieldRef),
GetFieldRefMut(IrGetFieldRefMut),
ReadField(IrReadField),
Load(IrExpression),
Add(IrAdd),
Subtract(IrSubtract),
@ -21,6 +27,15 @@ pub enum IrOperation {
impl Display for IrOperation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
IrOperation::GetFieldRef(ir_get_field_ref) => {
write!(f, "{}", ir_get_field_ref)
}
IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => {
write!(f, "{}", ir_get_field_ref_mut)
}
IrOperation::ReadField(ir_read_field) => {
write!(f, "{}", ir_read_field)
}
IrOperation::Load(ir_expression) => {
write!(f, "{}", ir_expression)
}
@ -46,6 +61,9 @@ impl Display for IrOperation {
impl VrUser for IrOperation {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
match self {
IrOperation::GetFieldRef(_) => HashSet::new(),
IrOperation::GetFieldRefMut(_) => HashSet::new(),
IrOperation::ReadField(_) => HashSet::new(),
IrOperation::Load(ir_expression) => ir_expression.vr_definitions(),
IrOperation::Add(ir_add) => ir_add.vr_definitions(),
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_definitions(),
@ -57,6 +75,9 @@ impl VrUser for IrOperation {
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
match self {
IrOperation::GetFieldRef(ir_get_field_ref) => ir_get_field_ref.vr_uses(),
IrOperation::GetFieldRefMut(ir_get_field_ref_mut) => ir_get_field_ref_mut.vr_uses(),
IrOperation::ReadField(ir_read_field) => ir_read_field.vr_uses(),
IrOperation::Load(ir_expression) => ir_expression.vr_uses(),
IrOperation::Add(ir_add) => ir_add.vr_uses(),
IrOperation::Subtract(ir_subtract) => ir_subtract.vr_uses(),
@ -68,6 +89,9 @@ impl VrUser for IrOperation {
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
match self {
IrOperation::GetFieldRef(_) => {}
IrOperation::GetFieldRefMut(_) => {}
IrOperation::ReadField(_) => {}
IrOperation::Load(ir_expression) => {
ir_expression.propagate_spills(spills);
}
@ -92,6 +116,9 @@ impl VrUser for IrOperation {
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
match self {
IrOperation::GetFieldRef(_) => {}
IrOperation::GetFieldRefMut(_) => {}
IrOperation::ReadField(_) => {}
IrOperation::Load(ir_expression) => {
ir_expression.propagate_register_assignments(assignments);
}

View File

@ -0,0 +1,52 @@
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
use std::rc::Rc;
pub struct IrReadField {
field_ref_variable: Rc<RefCell<IrVariable>>,
}
impl IrReadField {
pub fn new(field_ref_variable: Rc<RefCell<IrVariable>>) -> Self {
Self { field_ref_variable }
}
pub fn field_ref_variable(&self) -> &Rc<RefCell<IrVariable>> {
&self.field_ref_variable
}
}
impl Display for IrReadField {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.field_ref_variable.borrow(),)
}
}
impl VrUser for IrReadField {
fn vr_definitions(&self) -> HashSet<IrVrVariableDescriptor> {
HashSet::new()
}
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
let mut set = HashSet::new();
if let IrVariableDescriptor::VirtualRegister(vr_variable) =
self.field_ref_variable.borrow().descriptor()
{
set.insert(vr_variable.clone());
}
set
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {}
fn propagate_register_assignments(
&mut self,
assignments: &HashMap<IrVrVariableDescriptor, usize>,
) {
}
fn propagate_stack_offsets(&mut self, counter: &mut OffsetCounter) {}
}

View File

@ -4,27 +4,21 @@ use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
use crate::ir::register_allocation::{OffsetCounter, VrUser};
use crate::ir::util::propagate_spills;
use dvm_lib::instruction::{Instruction, Location};
use dvm_lib::instruction::Instruction;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::fmt::{Display, Formatter};
use std::rc::Rc;
pub struct IrSetField {
target_object: Rc<RefCell<IrVariable>>,
field_index: usize,
field_ref_variable: Rc<RefCell<IrVariable>>,
initializer: Box<IrExpression>,
}
impl IrSetField {
pub fn new(
target_object: &Rc<RefCell<IrVariable>>,
field_index: usize,
initializer: IrExpression,
) -> Self {
pub fn new(field_ref_variable: &Rc<RefCell<IrVariable>>, initializer: IrExpression) -> Self {
Self {
target_object: target_object.clone(),
field_index,
field_ref_variable: field_ref_variable.clone(),
initializer: initializer.into(),
}
}
@ -38,7 +32,7 @@ impl VrUser for IrSetField {
fn vr_uses(&self) -> HashSet<IrVrVariableDescriptor> {
let mut set = HashSet::new();
match self.target_object.borrow().descriptor() {
match self.field_ref_variable.borrow().descriptor() {
IrVariableDescriptor::VirtualRegister(vr_variable) => {
set.insert(vr_variable.clone());
}
@ -49,7 +43,7 @@ impl VrUser for IrSetField {
}
fn propagate_spills(&mut self, spills: &HashSet<IrVrVariableDescriptor>) {
propagate_spills(&mut self.target_object, spills);
propagate_spills(&mut self.field_ref_variable, spills);
self.initializer.propagate_spills(spills);
}
@ -67,21 +61,9 @@ impl VrUser for IrSetField {
impl Assemble for IrSetField {
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
let destination = match self.target_object.borrow().descriptor() {
IrVariableDescriptor::VirtualRegister(vr_variable) => {
Location::Register(vr_variable.assigned_register())
}
IrVariableDescriptor::Stack(stack_variable) => {
Location::StackFrameOffset(stack_variable.offset())
}
};
let field_ref_location = self.field_ref_variable.borrow().descriptor().as_location();
let set_field_operand = self.initializer.set_field_operand(constants_table);
builder.push(Instruction::SetField(
destination,
self.field_index,
set_field_operand,
));
builder.push(Instruction::SetField(field_ref_location, set_field_operand));
}
}
@ -89,9 +71,8 @@ impl Display for IrSetField {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}.{} = {}",
self.target_object.borrow(),
self.field_index,
"*{} = {}",
self.field_ref_variable.borrow(),
self.initializer
)
}

View File

@ -1,4 +1,5 @@
use crate::type_info::TypeInfo;
use dvm_lib::instruction::Location;
use std::fmt::{Debug, Display, Formatter};
use std::hash::Hash;
use std::rc::Rc;
@ -80,6 +81,15 @@ impl IrVariableDescriptor {
IrVariableDescriptor::Stack(stack_variable) => stack_variable.name_owned(),
}
}
pub fn as_location(&self) -> Location {
match self {
IrVariableDescriptor::VirtualRegister(register_variable) => {
register_variable.as_location()
}
IrVariableDescriptor::Stack(stack_variable) => stack_variable.as_location(),
}
}
}
#[derive(Clone, Hash, PartialEq, Eq)]
@ -117,6 +127,10 @@ impl IrVrVariableDescriptor {
pub fn assigned_register(&self) -> usize {
self.assigned_register.unwrap()
}
pub fn as_location(&self) -> Location {
Location::Register(self.assigned_register.unwrap())
}
}
impl Display for IrVrVariableDescriptor {
@ -161,6 +175,10 @@ impl IrStackVariableDescriptor {
pub fn offset(&self) -> isize {
self.offset.unwrap()
}
pub fn as_location(&self) -> Location {
Location::StackFrameOffset(self.offset.unwrap())
}
}
impl Display for IrStackVariableDescriptor {

View File

@ -6,9 +6,12 @@ pub mod ir_block;
pub mod ir_call;
pub mod ir_expression;
pub mod ir_function;
pub mod ir_get_field_ref;
pub mod ir_get_field_ref_mut;
pub mod ir_multiply;
pub mod ir_operation;
pub mod ir_parameter;
pub mod ir_read_field;
pub mod ir_return;
pub mod ir_set_field;
pub mod ir_statement;

View File

@ -1,5 +1,12 @@
use crate::ast::ir_builder::IrBuilder;
use crate::ir::ir_assign::IrAssign;
use crate::ir::ir_expression::IrExpression;
use crate::ir::ir_get_field_ref::IrGetFieldRef;
use crate::ir::ir_operation::IrOperation;
use crate::ir::ir_read_field::IrReadField;
use crate::ir::ir_statement::IrStatement;
use crate::ir::ir_variable::IrVariable;
use crate::symbol::Symbol;
use crate::symbol::class_symbol::ClassSymbol;
use crate::symbol::field_symbol::FieldSymbol;
use crate::symbol::function_symbol::FunctionSymbol;
@ -39,10 +46,58 @@ impl ExpressibleSymbol {
ExpressibleSymbol::Class(class_symbol) => {
todo!()
}
ExpressibleSymbol::Field(field_symbol) => IrExpression::Field(
builder.self_variable().clone(),
ExpressibleSymbol::Field(field_symbol) => {
// This following should work because blocks are flat in the ir; if a variable is
// defined in the ir block from this point forward, it's available to all subsequent
// blocks.
if !builder
.field_pointer_variables()
.contains_key(field_symbol.borrow().declared_name())
{
let field_ref_variable = IrVariable::new_vr(
builder.new_t_var().into(),
builder.current_block().id(),
field_symbol.borrow().type_info(),
);
let as_rc = Rc::new(RefCell::new(field_ref_variable));
let to_insert = as_rc.clone();
let self_variable = builder.self_variable().clone();
builder
.current_block_mut()
.add_statement(IrStatement::Assign(IrAssign::new(
as_rc,
IrOperation::GetFieldRef(IrGetFieldRef::new(
self_variable,
field_symbol.borrow().field_index(),
),
)),
)));
builder
.field_pointer_variables_mut()
.insert(field_symbol.borrow().declared_name_owned(), to_insert);
}
// now we need to read the field into a variable and return an expression pointing
// to that variable
let read_destination = IrVariable::new_vr(
builder.new_t_var().into(),
builder.current_block().id(),
field_symbol.borrow().type_info(),
);
let read_destination_as_rc = Rc::new(RefCell::new(read_destination));
let ir_read_field = IrReadField::new(
builder
.field_pointer_variables()
.get(field_symbol.borrow().declared_name())
.unwrap()
.clone(),
);
builder
.current_block_mut()
.add_statement(IrStatement::Assign(IrAssign::new(
read_destination_as_rc.clone(),
IrOperation::ReadField(ir_read_field),
)));
IrExpression::Variable(read_destination_as_rc)
}
ExpressibleSymbol::Function(_) => {
panic!("Cannot get ir_variable for FunctionSymbol");
}

View File

@ -18,8 +18,18 @@ pub enum Instruction {
InvokePlatformStatic(FunctionName, ArgCount),
Allocate(ClassFqn, Location),
GetField(Location, FieldIndex, Location),
SetField(Location, FieldIndex, SetFieldOperand),
/// (self_location, field_index, destination)
GetFieldPointer(Location, FieldIndex, Location),
/// (self_location, field_index, destination)
GetFieldPointerMut(Location, FieldIndex, Location),
/// (field_pointer_location, destination)
ReadField(Location, Location),
/// (field_pointer_mut_location, operand)
SetField(Location, SetFieldOperand),
Add(AddOperand, AddOperand, Location),
Subtract(SubtractOperand, SubtractOperand, Location),
@ -73,11 +83,26 @@ impl Display for Instruction {
Instruction::Allocate(class_fqn, location) => {
write!(f, "alloc {}, {}", class_fqn, location)
}
Instruction::GetField(source, field_index, destination) => {
write!(f, "getf {}.{}, {}", source, field_index, destination)
Instruction::GetFieldPointer(self_location, field_index, destination) => {
write!(
f,
"getf &{}.{}, {}",
self_location, field_index, destination
)
}
Instruction::SetField(target_location, field_index, operand) => {
write!(f, "setf {}.{}, {}", target_location, field_index, operand)
Instruction::GetFieldPointerMut(self_location, field_index, destination) => {
write!(
f,
"getf &mut {}.{}, {}",
self_location, field_index, destination
)
}
Instruction::ReadField(field_pointer_location, destination) => {
write!(f, "readf *{}, {}", field_pointer_location, destination)
}
Instruction::SetField(self_location, destination) => {
write!(f, "setf {}, {}", self_location, destination)
}
}
}
@ -86,8 +111,6 @@ impl Display for Instruction {
pub enum Location {
Register(Register),
StackFrameOffset(StackFrameOffset),
RegisterField(Register, FieldIndex),
StackFrameOffsetField(StackFrameOffset, FieldIndex),
}
impl Display for Location {
@ -103,16 +126,6 @@ impl Display for Location {
write!(f, "fp{}", offset)
}
}
Location::RegisterField(register, field_index) => {
write!(f, "r{}.{}", register, field_index)
}
Location::StackFrameOffsetField(offset, field_index) => {
if offset.is_positive() || *offset == 0 {
write!(f, "fp+{}.{}", offset, field_index)
} else {
write!(f, "fp-{}.{}", offset, field_index)
}
}
}
}
}

View File

@ -1,63 +0,0 @@
use crate::instruction::{AddOperand, MultiplyOperand, SubtractOperand};
use crate::vm::CallFrame;
use crate::vm::constant::Constant;
use crate::vm::value::Value;
use crate::vm::value_util::{load_constant_value, load_value};
use std::collections::HashMap;
use std::rc::Rc;
pub fn add_operand_to_value(
add_operand: &AddOperand,
registers: &[Value],
current_frame: &CallFrame,
constants: &HashMap<Rc<str>, Constant>,
) -> Value {
match add_operand {
AddOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
)
.clone(),
AddOperand::Int(i) => Value::Int(*i),
AddOperand::Double(d) => Value::Double(*d),
AddOperand::String(constant_name) => load_constant_value(constants, constant_name),
}
}
pub fn subtract_operand_to_value(
subtract_operand: &SubtractOperand,
registers: &[Value],
current_frame: &CallFrame,
) -> Value {
match subtract_operand {
SubtractOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
)
.clone(),
SubtractOperand::Int(i) => Value::Int(*i),
SubtractOperand::Double(d) => Value::Double(*d),
}
}
pub fn multiply_operand_to_value(
multiply_operand: &MultiplyOperand,
registers: &[Value],
current_frame: &CallFrame,
) -> Value {
match multiply_operand {
MultiplyOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
)
.clone(),
MultiplyOperand::Int(i) => Value::Int(*i),
MultiplyOperand::Double(d) => Value::Double(*d),
}
}

View File

@ -1,21 +1,25 @@
use crate::instruction::{Instruction, MoveOperand, PushOperand, ReturnOperand};
use crate::instruction::Instruction;
use crate::platform_function::PlatformFunction;
use crate::vm::constant::Constant;
use crate::vm::function::Function;
use crate::vm::instruction_helpers::{
add_operand_to_value, multiply_operand_to_value, subtract_operand_to_value,
use crate::vm::operand::Operand;
use crate::vm::operand_helpers::{
add_operand_to_value, move_operand_to_value, multiply_operand_to_value, push_operand_to_value,
return_operand_to_value, set_field_operand_to_value, subtract_operand_to_value,
};
use crate::vm::util::*;
use crate::vm::value::Value;
use crate::vm::value_util::*;
use std::collections::HashMap;
use std::ptr;
use std::rc::Rc;
pub mod constant;
pub mod function;
mod instruction_helpers;
pub mod object;
pub mod operand;
mod operand_helpers;
mod util;
pub mod value;
mod value_util;
pub struct DvmContext {
functions: HashMap<Rc<str>, Function>,
@ -61,7 +65,7 @@ pub struct CallFrame<'a> {
function: &'a Function,
instructions: &'a Vec<Instruction>,
ip: usize,
stack: Vec<Value>,
stack: Vec<Operand>,
fp: usize,
return_value: Option<Value>,
}
@ -94,11 +98,11 @@ impl<'a> CallFrame<'a> {
self.ip += 1;
}
fn stack(&self) -> &[Value] {
fn stack(&self) -> &[Operand] {
&self.stack
}
fn stack_mut(&mut self) -> &mut Vec<Value> {
fn stack_mut(&mut self) -> &mut Vec<Operand> {
&mut self.stack
}
@ -171,7 +175,7 @@ impl<'a> CallStack<'a> {
pub fn call<'a>(
context: &'a DvmContext,
registers: &mut Vec<Value>,
registers: &mut Vec<Operand>,
call_stack: &mut CallStack<'a>,
function_name: &str,
arguments: &[Value],
@ -191,7 +195,10 @@ pub fn call<'a>(
// put each arg on the stack
for argument in arguments {
call_stack.top_mut().stack_mut().push(argument.clone());
call_stack
.top_mut()
.stack_mut()
.push(Operand::Value(argument.clone()));
}
// set fp for this function
@ -200,7 +207,7 @@ pub fn call<'a>(
// ensure enough stack space
call_stack.top_mut().stack_mut().resize(
arguments.len() + (function.stack_size() as usize),
Value::Null,
Operand::Null,
);
// container for final return value
@ -219,41 +226,21 @@ pub fn call<'a>(
Instruction::Move(source, destination) => {
// move a value to a destination
// could be a copy or an immediate
let value = match source {
MoveOperand::Location(location) => load_value(
registers,
call_stack.top().stack(),
call_stack.top().fp(),
location,
)
.clone(),
MoveOperand::Int(i) => Value::Int(*i),
MoveOperand::Double(d) => Value::Double(*d),
MoveOperand::String(constant_name) => {
load_constant_value(context.constants(), constant_name)
}
};
let value =
move_operand_to_value(source, registers, call_stack.top(), context.constants());
put_value(registers, call_stack.top_mut(), destination, value);
call_stack.top_mut().increment_ip();
}
/* Push instructions */
Instruction::Push(operand) => {
let value = match operand {
PushOperand::Location(location) => load_value(
let value = push_operand_to_value(
operand,
registers,
call_stack.top().stack(),
call_stack.top().fp(),
location,
)
.clone(),
PushOperand::Double(d) => Value::Double(*d),
PushOperand::Int(i) => Value::Int(*i),
PushOperand::String(constant_name) => {
load_constant_value(context.constants(), constant_name)
}
};
call_stack.top_mut().stack_mut().push(value);
call_stack.top(),
context.constants(),
);
call_stack.top_mut().stack_mut().push(Operand::Value(value));
call_stack.top_mut().increment_ip();
}
@ -265,8 +252,13 @@ pub fn call<'a>(
.expect(&format!("Function {} not found", function_name));
// get args
let mut args =
call_stack.top().stack()[call_stack.top().stack().len() - arg_count..].to_vec();
// this isn't perfect (yet), but for now it works and satisfies the borrow checkers
let mut args = call_stack.top().stack()
[call_stack.top().stack().len() - arg_count..]
.iter()
.map(|operand| operand.unwrap_value().clone())
.map(|value| Operand::Value(value))
.collect::<Vec<_>>();
// save registers
for register in registers.iter_mut() {
@ -287,7 +279,7 @@ pub fn call<'a>(
call_stack
.top_mut()
.stack_mut()
.resize(arg_count + (function.stack_size() as usize), Value::Null);
.resize(arg_count + (function.stack_size() as usize), Operand::Null);
// set fp for callee frame
let callee_frame = call_stack.top_mut();
@ -300,14 +292,22 @@ pub fn call<'a>(
.get(function_name)
.expect(&format!("Platform function {} not found", function_name));
let args = &call_stack.top().stack()[call_stack.top().stack().len() - arg_count..];
let arg_operands =
&call_stack.top().stack()[call_stack.top().stack().len() - arg_count..];
let args = arg_operands
.iter()
.map(|operand| operand.unwrap_value().clone())
.collect::<Vec<_>>();
let result = platform_function(args);
let result = platform_function(&args);
match result {
Ok(return_value) => {
// push return value to top of caller stack if it's not null
if !matches!(return_value, Value::Null) {
call_stack.top_mut().stack_mut().push(return_value);
call_stack
.top_mut()
.stack_mut()
.push(Operand::Value(return_value));
}
}
Err(error) => {
@ -327,18 +327,77 @@ pub fn call<'a>(
todo!()
}
Instruction::GetField(source, field_index, destination) => {
// let object = load_value(...).unwrap_object();
// let field_value = object.fields()[field_index];
// put_value(..., destination, field_value.clone());
todo!()
Instruction::GetFieldPointer(self_location, field_index, destination) => {
let object = load_value(
registers,
call_stack.top().stack(),
call_stack.top().fp(),
self_location,
)
.unwrap_object()
.clone();
let field_ref = ptr::from_ref(&object.borrow_mut().fields_mut()[*field_index]);
put_operand(
registers,
call_stack.top_mut(),
destination,
Operand::FieldPointer(field_ref),
);
call_stack.top_mut().increment_ip();
}
Instruction::SetField(target, field_index, operand) => {
// let new_value = to_value(operand);
// let object = load_value(... target).unwrap_object();
// object.fields_mut()[field_index] = new_value;
todo!()
Instruction::GetFieldPointerMut(self_location, field_index, destination) => {
let object = load_value(
registers,
call_stack.top().stack(),
call_stack.top().fp(),
self_location,
)
.unwrap_object()
.clone();
let field_ref = ptr::from_mut(&mut object.borrow_mut().fields_mut()[*field_index]);
put_operand(
registers,
call_stack.top_mut(),
destination,
Operand::FieldPointerMut(field_ref),
);
call_stack.top_mut().increment_ip();
}
Instruction::ReadField(field_pointer_location, destination) => {
let field_pointer = load_operand(
registers,
call_stack.top().stack(),
call_stack.top().fp(),
field_pointer_location,
)
.unwrap_field_pointer();
// clone is very important, otherwise we mess up the self object!
let value = unsafe { field_pointer.read() }.clone();
put_value(registers, call_stack.top_mut(), destination, value);
call_stack.top_mut().increment_ip();
}
Instruction::SetField(field_point_mut_location, operand) => {
let fp = call_stack.top().fp(); // borrow checker :)
let field_pointer_mut = load_operand_mut(
registers,
call_stack.top_mut().stack_mut(),
fp,
field_point_mut_location,
)
.unwrap_field_pointer_mut();
let value = set_field_operand_to_value(
operand,
registers,
call_stack.top(),
context.constants(),
);
unsafe {
field_pointer_mut.write(value);
}
call_stack.top_mut().increment_ip();
}
/* Add instructions */
@ -442,27 +501,19 @@ pub fn call<'a>(
Instruction::Pop(maybe_location) => {
let value = call_stack.top_mut().stack_mut().pop().unwrap();
if let Some(location) = maybe_location {
put_value(registers, call_stack.top_mut(), location, value);
put_operand(registers, call_stack.top_mut(), location, value);
}
call_stack.top_mut().increment_ip();
}
/* Return instructions */
Instruction::SetReturnValue(return_operand) => {
let value = match return_operand {
ReturnOperand::Location(location) => load_value(
let value = return_operand_to_value(
return_operand,
registers,
call_stack.top().stack(),
call_stack.top().fp(),
location,
)
.clone(),
ReturnOperand::Int(i) => Value::Int(*i),
ReturnOperand::Double(d) => Value::Double(*d),
ReturnOperand::String(constant_name) => {
load_constant_value(context.constants(), constant_name)
}
};
call_stack.top(),
context.constants(),
);
call_stack.top_mut().set_return_value(value);
call_stack.top_mut().increment_ip();
}
@ -484,7 +535,7 @@ pub fn call<'a>(
// push return value if some
if let Some(return_value) = callee.take_return_value() {
// n.b. callee
caller.stack_mut().push(return_value);
caller.stack_mut().push(Operand::Value(return_value));
}
} else {
// callee is the bottommost frame ("main" or whatever was called)

51
dvm-lib/src/vm/operand.rs Normal file
View File

@ -0,0 +1,51 @@
use crate::vm::value::Value;
#[derive(Debug)]
pub enum Operand {
Value(Value),
FieldPointer(*const Value),
FieldPointerMut(*mut Value),
Null,
}
impl Operand {
pub fn unwrap_value(&self) -> &Value {
match self {
Operand::Value(value) => value,
_ => panic!("Attempt to unwrap {:?} as Value", self),
}
}
pub fn unwrap_field_pointer(&self) -> *const Value {
match self {
Operand::FieldPointer(p) => *p,
_ => panic!("Attempt to unwrap {:?} as FieldPointer", self),
}
}
pub fn unwrap_field_pointer_mut(&mut self) -> *mut Value {
match self {
Operand::FieldPointerMut(p) => *p,
_ => panic!("Attempt to unwrap {:?} as FieldPointerMut", self),
}
}
}
impl Default for Operand {
fn default() -> Self {
Operand::Null
}
}
impl Clone for Operand {
fn clone(&self) -> Self {
match self {
Operand::Value(value) => Operand::Value(Value::clone(value)),
Operand::FieldPointer(field_ref) => Operand::FieldPointer(*field_ref),
Operand::FieldPointerMut(_) => {
panic!("Cannot clone FieldRefMut")
}
Operand::Null => Operand::Null,
}
}
}

View File

@ -0,0 +1,140 @@
use crate::instruction::{
AddOperand, MoveOperand, MultiplyOperand, PushOperand, ReturnOperand, SetFieldOperand,
SubtractOperand,
};
use crate::vm::CallFrame;
use crate::vm::constant::Constant;
use crate::vm::operand::Operand;
use crate::vm::util::{load_constant_value, load_value};
use crate::vm::value::Value;
use std::collections::HashMap;
use std::rc::Rc;
pub fn move_operand_to_value(
move_operand: &MoveOperand,
registers: &[Operand],
current_frame: &CallFrame,
constants: &HashMap<Rc<str>, Constant>,
) -> Value {
match move_operand {
MoveOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
),
MoveOperand::Int(i) => Value::Int(*i),
MoveOperand::Double(d) => Value::Double(*d),
MoveOperand::String(constant_name) => load_constant_value(constants, constant_name),
}
}
pub fn push_operand_to_value(
push_operand: &PushOperand,
registers: &[Operand],
current_frame: &CallFrame,
constants: &HashMap<Rc<str>, Constant>,
) -> Value {
match push_operand {
PushOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
),
PushOperand::Double(d) => Value::Double(*d),
PushOperand::Int(i) => Value::Int(*i),
PushOperand::String(constant_name) => load_constant_value(constants, constant_name),
}
}
pub fn add_operand_to_value(
add_operand: &AddOperand,
registers: &[Operand],
current_frame: &CallFrame,
constants: &HashMap<Rc<str>, Constant>,
) -> Value {
match add_operand {
AddOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
),
AddOperand::Int(i) => Value::Int(*i),
AddOperand::Double(d) => Value::Double(*d),
AddOperand::String(constant_name) => load_constant_value(constants, constant_name),
}
}
pub fn subtract_operand_to_value(
subtract_operand: &SubtractOperand,
registers: &[Operand],
current_frame: &CallFrame,
) -> Value {
match subtract_operand {
SubtractOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
),
SubtractOperand::Int(i) => Value::Int(*i),
SubtractOperand::Double(d) => Value::Double(*d),
}
}
pub fn multiply_operand_to_value(
multiply_operand: &MultiplyOperand,
registers: &[Operand],
current_frame: &CallFrame,
) -> Value {
match multiply_operand {
MultiplyOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
),
MultiplyOperand::Int(i) => Value::Int(*i),
MultiplyOperand::Double(d) => Value::Double(*d),
}
}
pub fn return_operand_to_value(
return_operand: &ReturnOperand,
registers: &[Operand],
current_frame: &CallFrame,
constants: &HashMap<Rc<str>, Constant>,
) -> Value {
match return_operand {
ReturnOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
),
ReturnOperand::Int(i) => Value::Int(*i),
ReturnOperand::Double(d) => Value::Double(*d),
ReturnOperand::String(constant_name) => load_constant_value(constants, constant_name),
}
}
pub fn set_field_operand_to_value(
set_field_operand: &SetFieldOperand,
registers: &[Operand],
current_frame: &CallFrame,
constants: &HashMap<Rc<str>, Constant>,
) -> Value {
match set_field_operand {
SetFieldOperand::Location(location) => load_value(
registers,
current_frame.stack(),
current_frame.fp(),
location,
),
SetFieldOperand::Int(i) => Value::Int(*i),
SetFieldOperand::Double(d) => Value::Double(*d),
SetFieldOperand::String(constant_name) => load_constant_value(constants, constant_name),
}
}

90
dvm-lib/src/vm/util.rs Normal file
View File

@ -0,0 +1,90 @@
use crate::instruction::{ConstantName, Location};
use crate::vm::CallFrame;
use crate::vm::constant::Constant;
use crate::vm::operand::Operand;
use crate::vm::value::Value;
use std::collections::HashMap;
use std::rc::Rc;
#[inline]
fn calculate_from_offset(fp: usize, offset: isize) -> usize {
fp.checked_add_signed(offset).expect(&format!(
"Overflow when adding offset {} to fp {}",
offset, fp
))
}
pub fn load_operand<'a>(
registers: &'a [Operand],
stack: &'a [Operand],
fp: usize,
location: &Location,
) -> &'a Operand {
match location {
Location::Register(register) => &registers[*register],
Location::StackFrameOffset(offset) => &stack[calculate_from_offset(fp, *offset)],
}
}
pub fn load_operand_mut<'a>(
registers: &'a mut [Operand],
stack: &'a mut [Operand],
fp: usize,
location: &Location,
) -> &'a mut Operand {
match location {
Location::Register(register) => &mut registers[*register],
Location::StackFrameOffset(offset) => &mut stack[calculate_from_offset(fp, *offset)],
}
}
pub fn load_value(
registers: &[Operand],
stack: &[Operand],
fp: usize,
location: &Location,
) -> Value {
load_operand(registers, stack, fp, location)
.unwrap_value()
.clone()
}
pub fn load_constant_value(
constants: &HashMap<Rc<str>, Constant>,
constant_name: &ConstantName,
) -> Value {
let constant = &constants[constant_name];
match constant {
Constant::String(string_constant) => Value::String(string_constant.content_owned()),
}
}
pub fn put_operand(
registers: &mut Vec<Operand>,
current_frame: &mut CallFrame,
destination: &Location,
operand: Operand,
) {
match destination {
Location::Register(register) => {
registers[*register] = operand;
}
Location::StackFrameOffset(offset) => {
let fp = current_frame.fp();
let target_index = fp.checked_add_signed(*offset).expect(&format!(
"Failed to calculate target index from fp + offset ({} + {})",
fp, offset
));
current_frame.stack_mut()[target_index] = operand;
}
}
}
pub fn put_value(
registers: &mut Vec<Operand>,
current_frame: &mut CallFrame,
destination: &Location,
value: Value,
) {
put_operand(registers, current_frame, destination, Operand::Value(value));
}

View File

@ -1,4 +1,5 @@
use crate::vm::object::Object;
use std::cell::RefCell;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
@ -38,11 +39,11 @@ impl Value {
}
}
pub fn unwrap_object(&self) -> &Object {
pub fn unwrap_object(&self) -> &Rc<RefCell<Object>> {
todo!()
}
pub fn unwrap_object_mut(&mut self) -> &mut Object {
pub fn unwrap_object_mut(&mut self) -> &mut Rc<RefCell<Object>> {
todo!()
}
}

View File

@ -1,78 +0,0 @@
use crate::instruction::{ConstantName, Location};
use crate::vm::CallFrame;
use crate::vm::constant::Constant;
use crate::vm::value::Value;
use std::collections::HashMap;
use std::rc::Rc;
pub fn load_value<'a>(
registers: &'a [Value],
stack: &'a [Value],
fp: usize,
location: &Location,
) -> &'a Value {
match location {
Location::Register(register) => &registers[*register],
Location::StackFrameOffset(offset) => {
let value_index = fp.checked_add_signed(*offset).expect(&format!(
"Overflow when adding offset {} to fp {}",
*offset, fp
));
&stack[value_index]
}
Location::RegisterField(register, field_index) => {
&registers[*register].unwrap_object().fields()[*field_index]
}
Location::StackFrameOffsetField(offset, field_index) => {
let value_index = fp.checked_add_signed(*offset).expect(&format!(
"Overflow when adding offset {} to fp {}",
*offset, fp
));
&stack[value_index].unwrap_object().fields()[*field_index]
}
}
}
pub fn load_constant_value(
constants: &HashMap<Rc<str>, Constant>,
constant_name: &ConstantName,
) -> Value {
let constant = &constants[constant_name];
match constant {
Constant::String(string_constant) => Value::String(string_constant.content_owned()),
}
}
pub fn put_value(
registers: &mut Vec<Value>,
current_frame: &mut CallFrame,
destination: &Location,
value: Value,
) {
match destination {
Location::Register(register) => {
registers[*register] = value;
}
Location::StackFrameOffset(offset) => {
let fp = current_frame.fp();
let target_index = fp.checked_add_signed(*offset).expect(&format!(
"Failed to calculate target index from fp + offset ({} + {})",
fp, offset
));
current_frame.stack_mut()[target_index] = value;
}
Location::RegisterField(register, field_index) => {
registers[*register].unwrap_object_mut().fields_mut()[*field_index] = value;
}
Location::StackFrameOffsetField(offset, field_index) => {
let fp = current_frame.fp();
let target_index = fp.checked_add_signed(*offset).expect(&format!(
"Failed to calculate target index from fp + offset ({} + {})",
fp, offset
));
current_frame.stack_mut()[target_index]
.unwrap_object_mut()
.fields_mut()[*field_index] = value;
}
}
}

View File

@ -6,6 +6,7 @@ mod e2e_tests {
use dmc_lib::symbol_table::SymbolTable;
use dvm_lib::vm::constant::{Constant, StringConstant};
use dvm_lib::vm::function::Function;
use dvm_lib::vm::operand::Operand;
use dvm_lib::vm::value::Value;
use dvm_lib::vm::{CallStack, DvmContext, call};
use std::rc::Rc;
@ -90,7 +91,7 @@ mod e2e_tests {
function_name: &str,
arguments: &[Value],
) -> Option<Value> {
let mut registers: Vec<Value> = vec![Value::Null; REGISTER_COUNT];
let mut registers: Vec<Operand> = vec![Operand::Null; REGISTER_COUNT];
let mut call_stack = CallStack::new();
call(