Update calling conventions.
This commit is contained in:
parent
1263d84802
commit
ae8f89bb4e
@ -1,7 +1,7 @@
|
||||
use deimos::object_file::{DvmObjectFile, DvmPath};
|
||||
use deimos::vm::constant::DvmConstant;
|
||||
use deimos::vm::function::DvmFunction;
|
||||
use deimos::vm::instruction::{Immediate, Instruction, Location};
|
||||
use deimos::vm::instruction::{Immediate, Instruction};
|
||||
use deimos::vm::platform::get_std_lib_platform_functions;
|
||||
use deimos::vm::source_code_location::SourceCodeLocation;
|
||||
use deimos::vm::{dump_state, run_main_function, DvmContext, DvmState};
|
||||
@ -16,16 +16,23 @@ fn main() {
|
||||
//
|
||||
// fn main() {
|
||||
// println "Hello, World!"
|
||||
// println foo()
|
||||
// }
|
||||
//
|
||||
// fn foo() = 42
|
||||
let mut greeter_object_file = DvmObjectFile::new(DvmPath::new("greeter", "greeter.dmo"));
|
||||
|
||||
use Instruction::*;
|
||||
let main_instructions = vec![
|
||||
Instruction::MoveImmediate {
|
||||
destination: Location::Register(0),
|
||||
MoveImmediate {
|
||||
destination_register: 0,
|
||||
immediate: Immediate::Constant(DvmConstant::String(String::from("Hello, World!"))),
|
||||
},
|
||||
Instruction::Push { source_register: 0 },
|
||||
Instruction::InvokeStaticPlatform {
|
||||
// prepare for call to println
|
||||
Push { source_register: 0 }, // save r0
|
||||
Push { source_register: 0 }, // arg0
|
||||
// call
|
||||
InvokeStaticPlatform {
|
||||
function_name: Rc::new(String::from("std::core::println")),
|
||||
source_code_location: SourceCodeLocation {
|
||||
source_file_name: String::from("greeter.dm"),
|
||||
@ -33,20 +40,55 @@ fn main() {
|
||||
char: 5,
|
||||
},
|
||||
},
|
||||
Instruction::Pop {
|
||||
// println return value
|
||||
// unwind from call
|
||||
Pop {
|
||||
destination_register: None,
|
||||
}, // arg0
|
||||
Pop {
|
||||
destination_register: Some(0), // restore r0
|
||||
},
|
||||
Instruction::Pop {
|
||||
// arg0 to println
|
||||
// prepare for call to foo
|
||||
Push { source_register: 0 }, // save r0
|
||||
InvokeStatic {
|
||||
function_name: Rc::new(String::from("greeter::foo")),
|
||||
source_code_location: SourceCodeLocation {
|
||||
source_file_name: String::from("greeter.dm"),
|
||||
line: 5,
|
||||
char: 13,
|
||||
},
|
||||
},
|
||||
Pop { destination_register: Some(0) }, // restore r0
|
||||
TakeReturnValue {
|
||||
destination_register: 1,
|
||||
},
|
||||
// call println again
|
||||
Push { source_register: 1 }, // save r1
|
||||
Push { source_register: 0 }, // save r0
|
||||
Push { source_register: 1 }, // arg0
|
||||
InvokeStaticPlatform {
|
||||
function_name: Rc::new(String::from("std::core::println")),
|
||||
source_code_location: SourceCodeLocation {
|
||||
source_file_name: String::from("greeter.dm"),
|
||||
line: 5,
|
||||
char: 5,
|
||||
},
|
||||
},
|
||||
Pop {
|
||||
destination_register: None,
|
||||
}, // arg0
|
||||
Pop {
|
||||
destination_register: Some(0), // restore r0
|
||||
},
|
||||
Instruction::MoveImmediate {
|
||||
destination: Location::Register(1),
|
||||
Pop {
|
||||
destination_register: Some(1), // restore r1
|
||||
},
|
||||
// return 0
|
||||
MoveImmediate {
|
||||
destination_register: 2,
|
||||
immediate: Immediate::Int(0),
|
||||
},
|
||||
Instruction::Push { source_register: 1 },
|
||||
Instruction::Return,
|
||||
SetReturnValue { source_register: 2 },
|
||||
Return, // explicit, not needed
|
||||
];
|
||||
|
||||
let main_function = DvmFunction::new(
|
||||
@ -59,14 +101,32 @@ fn main() {
|
||||
},
|
||||
);
|
||||
|
||||
let foo_function_instructions = vec![
|
||||
MoveImmediate {
|
||||
destination_register: 0,
|
||||
immediate: Immediate::Int(42),
|
||||
},
|
||||
SetReturnValue { source_register: 0 },
|
||||
Return, // explicit, not needed
|
||||
];
|
||||
|
||||
let foo_function = DvmFunction::new(
|
||||
"greeter::foo",
|
||||
&foo_function_instructions,
|
||||
SourceCodeLocation {
|
||||
source_file_name: String::from("greeter.dm"),
|
||||
line: 8,
|
||||
char: 1,
|
||||
},
|
||||
);
|
||||
|
||||
greeter_object_file.add_function(main_function);
|
||||
greeter_object_file.add_function(foo_function);
|
||||
|
||||
let mut state = DvmState::new();
|
||||
let mut context = DvmContext::new("greeter::main");
|
||||
context.add_platform_functions(get_std_lib_platform_functions());
|
||||
greeter_object_file.load_to_context(&mut context, &|path| {
|
||||
todo!()
|
||||
});
|
||||
greeter_object_file.load_to_context(&mut context, &|path| todo!());
|
||||
|
||||
let exit_code = run_main_function(&mut state, &context);
|
||||
|
||||
|
@ -5,7 +5,7 @@ use std::rc::Rc;
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Instruction {
|
||||
MoveImmediate {
|
||||
destination: Location,
|
||||
destination_register: usize,
|
||||
immediate: Immediate,
|
||||
},
|
||||
Copy {
|
||||
@ -40,6 +40,12 @@ pub enum Instruction {
|
||||
function_name: Rc<String>,
|
||||
source_code_location: SourceCodeLocation,
|
||||
},
|
||||
SetReturnValue {
|
||||
source_register: usize,
|
||||
},
|
||||
TakeReturnValue {
|
||||
destination_register: usize,
|
||||
},
|
||||
Add {
|
||||
left: u8,
|
||||
right: u8,
|
||||
@ -104,6 +110,9 @@ pub enum Instruction {
|
||||
offset: isize,
|
||||
},
|
||||
Return,
|
||||
DumpState {
|
||||
message: String
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -121,8 +130,11 @@ pub enum Immediate {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Location {
|
||||
Register(usize),
|
||||
Stack {
|
||||
offset: usize,
|
||||
StackFrameBase {
|
||||
offset: isize,
|
||||
},
|
||||
StackTop {
|
||||
offset: isize,
|
||||
},
|
||||
Field {
|
||||
object_register: usize,
|
||||
@ -131,6 +143,6 @@ pub enum Location {
|
||||
Array {
|
||||
array_register: usize,
|
||||
index_register: usize,
|
||||
offset: Option<isize>,
|
||||
offset: isize,
|
||||
},
|
||||
}
|
||||
|
138
src/vm/mod.rs
138
src/vm/mod.rs
@ -43,10 +43,12 @@ pub fn dump_state(state: &DvmState, message: &str) {
|
||||
for (i, register) in state.registers.iter().enumerate() {
|
||||
println!("\tr{:x}: {:?}", i, register);
|
||||
}
|
||||
println!("Return value register: {}", state.return_value_register);
|
||||
println!("Call stack:");
|
||||
for call in state.call_stack.iter() {
|
||||
println!("\t{}", call);
|
||||
}
|
||||
println!("Frame base index: {}", state.frame_base_index);
|
||||
println!("Stack:");
|
||||
for (i, value) in state.stack.iter().enumerate() {
|
||||
println!("\t{}: {}", i, value);
|
||||
@ -63,10 +65,13 @@ macro_rules! dvm_panic {
|
||||
|
||||
pub type PlatformFunction = fn(state: &mut DvmState, context: &DvmContext);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DvmState {
|
||||
call_stack: Vec<DvmCall>,
|
||||
current_instruction: Option<Instruction>,
|
||||
frame_base_index: usize,
|
||||
registers: Vec<DvmValue>,
|
||||
return_value_register: DvmValue,
|
||||
stack: Vec<DvmValue>,
|
||||
}
|
||||
|
||||
@ -75,7 +80,9 @@ impl DvmState {
|
||||
DvmState {
|
||||
call_stack: vec![],
|
||||
current_instruction: None,
|
||||
frame_base_index: 0,
|
||||
registers: vec![DvmValue::Empty; 16],
|
||||
return_value_register: DvmValue::Empty,
|
||||
stack: vec![],
|
||||
}
|
||||
}
|
||||
@ -87,8 +94,14 @@ impl DvmState {
|
||||
}
|
||||
|
||||
pub fn get_stack_argument(&self, index: usize) -> DvmValue {
|
||||
let target_index = self
|
||||
.frame_base_index
|
||||
.checked_sub(1 + index)
|
||||
.unwrap_or_else(|| {
|
||||
dvm_panic!(self, "Unsigned overflow: calculated negative target_index.");
|
||||
});
|
||||
self.stack
|
||||
.get(self.stack.len() - 2 - index)
|
||||
.get(target_index)
|
||||
.unwrap_or_else(|| {
|
||||
dvm_panic!(self, "Stack underflow!");
|
||||
})
|
||||
@ -150,6 +163,7 @@ impl DvmContext {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DvmCall {
|
||||
function_name: Rc<String>,
|
||||
source_code_location: SourceCodeLocation,
|
||||
@ -169,9 +183,9 @@ impl Display for DvmCall {
|
||||
|
||||
fn update_index(index: &mut usize, offset: isize) {
|
||||
if offset.is_negative() {
|
||||
*index -= offset.abs() as usize;
|
||||
*index -= offset.unsigned_abs();
|
||||
} else {
|
||||
*index += offset as usize;
|
||||
*index += offset.unsigned_abs();
|
||||
}
|
||||
}
|
||||
|
||||
@ -193,27 +207,40 @@ fn pop_call_frame(state: &mut DvmState) {
|
||||
fn compute_index_with_offset(
|
||||
registers: &Vec<DvmValue>,
|
||||
index_register: usize,
|
||||
offset: &Option<isize>,
|
||||
offset: isize,
|
||||
) -> usize {
|
||||
let index = registers[index_register].as_usize().expect(&format!(
|
||||
"Could not convert the value of index_register {} to usize; found {:?}",
|
||||
index_register, registers[index_register]
|
||||
));
|
||||
if let Some(o) = offset {
|
||||
if o.is_negative() {
|
||||
index - o.unsigned_abs()
|
||||
} else {
|
||||
index + o.unsigned_abs()
|
||||
}
|
||||
if offset.is_negative() {
|
||||
index - offset.unsigned_abs()
|
||||
} else {
|
||||
index
|
||||
index + offset.unsigned_abs()
|
||||
}
|
||||
}
|
||||
|
||||
fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue {
|
||||
match source {
|
||||
Location::Register(register) => state.registers[*register].clone(),
|
||||
Location::Stack { offset } => state.stack[*offset].clone(),
|
||||
Location::StackFrameBase { offset } => {
|
||||
let index = if offset.is_negative() {
|
||||
state.frame_base_index - offset.unsigned_abs()
|
||||
} else {
|
||||
state.frame_base_index + offset.unsigned_abs()
|
||||
};
|
||||
state.stack[index].clone()
|
||||
}
|
||||
Location::StackTop { offset } => {
|
||||
if *offset >= 0 {
|
||||
dvm_panic!(
|
||||
state,
|
||||
&format!("Offset {} out of bounds (must be negative)", offset)
|
||||
);
|
||||
}
|
||||
let stack_length = state.stack.len();
|
||||
state.stack[stack_length - offset.unsigned_abs()].clone()
|
||||
}
|
||||
Location::Field {
|
||||
object_register,
|
||||
field_name,
|
||||
@ -228,7 +255,7 @@ fn copy_from_source(state: &DvmState, source: &Location) -> DvmValue {
|
||||
index_register,
|
||||
offset,
|
||||
} => {
|
||||
let index = compute_index_with_offset(&state.registers, *index_register, offset);
|
||||
let index = compute_index_with_offset(&state.registers, *index_register, *offset);
|
||||
state.registers[*array_register].map_array(
|
||||
|a| a.borrow().read_element(index),
|
||||
|v| {
|
||||
@ -244,8 +271,26 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm
|
||||
Location::Register(register) => {
|
||||
state.registers[*register] = value;
|
||||
}
|
||||
Location::Stack { offset } => {
|
||||
state.stack[*offset] = value;
|
||||
Location::StackFrameBase { offset } => {
|
||||
let index = if offset.is_negative() {
|
||||
state.frame_base_index - offset.unsigned_abs()
|
||||
} else {
|
||||
state.frame_base_index + offset.unsigned_abs()
|
||||
};
|
||||
state.stack[index] = value;
|
||||
}
|
||||
Location::StackTop { offset } => {
|
||||
if *offset >= 0 {
|
||||
dvm_panic!(
|
||||
state,
|
||||
&format!(
|
||||
"Stack top offset {} is out of range (must be negative)",
|
||||
offset
|
||||
)
|
||||
);
|
||||
}
|
||||
let stack_length = state.stack.len();
|
||||
state.stack[stack_length - offset.unsigned_abs()] = value;
|
||||
}
|
||||
Location::Field {
|
||||
object_register,
|
||||
@ -261,7 +306,7 @@ fn write_to_destination(state: &mut DvmState, destination: &Location, value: Dvm
|
||||
index_register,
|
||||
offset,
|
||||
} => {
|
||||
let index = compute_index_with_offset(&state.registers, *index_register, offset);
|
||||
let index = compute_index_with_offset(&state.registers, *index_register, *offset);
|
||||
state.registers[*array_register]
|
||||
.expect_array()
|
||||
.borrow_mut()
|
||||
@ -310,7 +355,9 @@ fn immediate_to_value(immediate: &Immediate) -> DvmValue {
|
||||
}
|
||||
|
||||
pub fn run_main_function(state: &mut DvmState, context: &DvmContext) -> i32 {
|
||||
let main_function = context.static_functions.get(&context.main_function)
|
||||
let main_function = context
|
||||
.static_functions
|
||||
.get(&context.main_function)
|
||||
.expect(&format!("No such main function: {}", context.main_function));
|
||||
push_call_frame(
|
||||
Rc::new(main_function.fqn().to_string()),
|
||||
@ -319,23 +366,29 @@ pub fn run_main_function(state: &mut DvmState, context: &DvmContext) -> i32 {
|
||||
);
|
||||
run(main_function.instructions(), state, context);
|
||||
pop_call_frame(state);
|
||||
state.pop_stack().expect_int_or_else(|v| {
|
||||
dvm_panic!(state, &format!("Expected DvmValue::Int, but found {}", v));
|
||||
state.return_value_register.expect_int_or_else(|v| {
|
||||
dvm_panic!(
|
||||
state,
|
||||
&format!("Expected main to return DvmValue::Int, but found {}", v)
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: find all possible unwraps/expects and wrap with call to dvm_panic
|
||||
pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmContext) {
|
||||
state.frame_base_index = state.stack.len();
|
||||
let mut index = 0;
|
||||
while index < instructions.len() {
|
||||
state.current_instruction = Some(instructions[index].clone());
|
||||
let current_instruction = &instructions[index];
|
||||
state.current_instruction = Some(current_instruction.clone());
|
||||
index += 1;
|
||||
use Instruction::*;
|
||||
match &instructions[index] {
|
||||
match current_instruction {
|
||||
MoveImmediate {
|
||||
destination,
|
||||
destination_register,
|
||||
immediate,
|
||||
} => {
|
||||
write_to_destination(state, destination, immediate_to_value(immediate));
|
||||
state.registers[*destination_register] = immediate_to_value(immediate);
|
||||
}
|
||||
Copy {
|
||||
source,
|
||||
@ -392,9 +445,18 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont
|
||||
.clone();
|
||||
|
||||
// Do call
|
||||
state.stack.push(DvmValue::Empty); // space for return value
|
||||
// before:
|
||||
// - push call frame
|
||||
// - save current frame base index
|
||||
// - set current frame base index to current stack size
|
||||
push_call_frame(function_name.clone(), source_code_location.clone(), state);
|
||||
let saved_frame_base_index = state.frame_base_index;
|
||||
state.frame_base_index = state.stack.len();
|
||||
// actual call
|
||||
run(static_function.instructions(), state, context);
|
||||
|
||||
// reverse order
|
||||
state.frame_base_index = saved_frame_base_index;
|
||||
pop_call_frame(state);
|
||||
}
|
||||
InvokeObject {
|
||||
@ -426,12 +488,12 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont
|
||||
let instructions = function.instructions();
|
||||
|
||||
// Do call
|
||||
state.stack.push(DvmValue::Empty); // space for return value
|
||||
state.stack.push(object_value); // self object
|
||||
push_call_frame(function_name.clone(), source_code_location.clone(), state);
|
||||
let saved_frame_base_index = state.frame_base_index;
|
||||
state.frame_base_index = state.stack.len();
|
||||
run(instructions, state, context);
|
||||
state.frame_base_index = saved_frame_base_index;
|
||||
pop_call_frame(state);
|
||||
state.stack.pop(); // self object
|
||||
}
|
||||
InvokeStaticPlatform {
|
||||
function_name,
|
||||
@ -449,9 +511,11 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont
|
||||
});
|
||||
|
||||
// Do call
|
||||
state.stack.push(DvmValue::Empty); // space for return value
|
||||
push_call_frame(function_name.clone(), source_code_location.clone(), state);
|
||||
let saved_frame_base_index = state.frame_base_index;
|
||||
state.frame_base_index = state.stack.len();
|
||||
platform_function(state, context);
|
||||
state.frame_base_index = saved_frame_base_index;
|
||||
pop_call_frame(state);
|
||||
}
|
||||
InvokeObjectPlatform {
|
||||
@ -483,12 +547,22 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont
|
||||
}
|
||||
|
||||
// Do call
|
||||
state.stack.push(DvmValue::Empty); // space for return value
|
||||
state.stack.push(object_value); // self object
|
||||
push_call_frame(function_name.clone(), source_code_location.clone(), state);
|
||||
let saved_frame_base_index = state.frame_base_index;
|
||||
state.frame_base_index = state.stack.len();
|
||||
object_platform_function(state, context);
|
||||
state.frame_base_index = saved_frame_base_index;
|
||||
pop_call_frame(state);
|
||||
state.stack.pop(); // self object
|
||||
}
|
||||
SetReturnValue { source_register } => {
|
||||
state.return_value_register =
|
||||
std::mem::take(&mut state.registers[*source_register]);
|
||||
}
|
||||
TakeReturnValue {
|
||||
destination_register,
|
||||
} => {
|
||||
state.registers[*destination_register] =
|
||||
std::mem::take(&mut state.return_value_register);
|
||||
}
|
||||
Add { .. } => {}
|
||||
Subtract { .. } => {}
|
||||
@ -518,7 +592,7 @@ pub fn run(instructions: &[Instruction], state: &mut DvmState, context: &DvmCont
|
||||
Return => {
|
||||
break;
|
||||
}
|
||||
DumpState { message } => dump_state(state, message),
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user