Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aria-bin/src/file_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fn eval_buffer(
println!("Module dump:\n{output}\n");
}

let r_module = match RuntimeModule::new(c_module) {
let r_module = match RuntimeModule::new(vm, c_module) {
Ok(m) => m,
Err(err) => {
return Err(print_report_from_vm_error(&err.into()));
Expand Down
4 changes: 2 additions & 2 deletions aria-bin/src/repl_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ impl<'a> Repl<'a> {
}
};

let r_module = match RuntimeModule::new(c_module) {
let r_module = match RuntimeModule::new(&mut vm, c_module) {
Ok(m) => m,
Err(err) => {
return Err(print_report_from_vm_error(&err.into()));
Expand Down Expand Up @@ -278,7 +278,7 @@ impl<'a> Repl<'a> {
println!("Module dump:\n{output}\n");
}

let r_module = match RuntimeModule::new(c_module) {
let r_module = match RuntimeModule::new(&mut self.vm, c_module) {
Ok(m) => m,
Err(err) => {
return Err(self.print_error_report(build_report_from_vm_error(&err.into())));
Expand Down
13 changes: 13 additions & 0 deletions vm-lib/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::{
kind::RuntimeValueType,
object::ObjectBox,
},
symbol::Interner,
};

mod alloc;
Expand Down Expand Up @@ -70,6 +71,7 @@ impl AriaBuiltinTypes {
pub struct VmGlobals {
values: Rc<ObjectBox>,
builtin_types: AriaBuiltinTypes,
interner: Interner,
}

impl VmGlobals {
Expand Down Expand Up @@ -119,6 +121,7 @@ impl Default for VmGlobals {
let mut this = Self {
values: Default::default(),
builtin_types: Default::default(),
interner: Default::default(),
};

this.register_builtin_type(BuiltinTypeId::Any, RuntimeValueType::Any); // Most anything needs Any
Expand Down Expand Up @@ -162,6 +165,16 @@ impl Default for VmGlobals {
}

impl VmGlobals {
pub fn intern_symbol(&mut self, s: &str) -> Result<crate::symbol::Symbol, VmErrorReason> {
self.interner.intern(s).map_err(|e| match e {
crate::symbol::InternError::TooManySymbols => VmErrorReason::TooManyInternedSymbols,
})
}

pub fn resolve_symbol(&self, sym: crate::symbol::Symbol) -> Option<&str> {
self.interner.resolve(sym)
}

pub fn load_named_value(&self, name: &str) -> Option<RuntimeValue> {
self.values.read(name)
}
Expand Down
3 changes: 3 additions & 0 deletions vm-lib/src/error/vm_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ pub enum VmErrorReason {
#[error("bytecode exceeds maximum allowed size")]
BytecodeTooLarge,

#[error("too many symbols have been interned")]
TooManyInternedSymbols,

#[error("VM execution halted")]
VmHalted,
}
Expand Down
1 change: 1 addition & 0 deletions vm-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod opcodes;
pub mod runtime_module;
pub mod runtime_value;
pub mod stack;
pub mod symbol;
pub mod vm;

#[cfg(test)]
Expand Down
102 changes: 97 additions & 5 deletions vm-lib/src/runtime_module.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// SPDX-License-Identifier: Apache-2.0
use std::{cell::RefCell, collections::HashSet, rc::Rc};

use aria_compiler::{bc_reader::DecodeError, module::CompiledModule};
use aria_compiler::module::CompiledModule;
use haxby_opcodes::Opcode;
use rustc_data_structures::fx::FxHashMap;

use crate::{
Expand All @@ -12,6 +13,7 @@ use crate::{
function::{BuiltinFunctionImpl, Function},
isa::IsaCheckable,
},
vm::VirtualMachine,
};

#[derive(Clone)]
Expand All @@ -24,14 +26,100 @@ struct RuntimeModuleImpl {
compiled_module: CompiledModule,
indexed_constants: Vec<RuntimeValue>,
values: RefCell<FxHashMap<String, NamedValue>>,
entry_co: crate::runtime_value::runtime_code_object::CodeObject,
}

fn byte_array_to_opcode_array(bytes: &[u8]) -> aria_compiler::bc_reader::DecodeResult<Vec<Opcode>> {
let mut opcodes = Vec::new();
let mut decoder = aria_compiler::bc_reader::BytecodeReader::try_from(bytes)?;

loop {
let next = decoder.read_opcode();
match next {
Ok(op) => opcodes.push(op),
Err(err) => {
return match err {
aria_compiler::bc_reader::DecodeError::EndOfStream => Ok(opcodes),
_ => Err(err),
};
}
}
}
}

fn replace_attribute_access_with_interned(
vm: &mut VirtualMachine,
cm: &CompiledModule,
opcodes: &mut Vec<Opcode>,
) -> Result<(), VmErrorReason> {
for opcode in opcodes {
match opcode {
Opcode::ReadAttribute(n) | Opcode::WriteAttribute(n) => {
let x_str = cm
.load_indexed_const(*n)
.expect("missing constant")
.as_string()
.expect("expected string constant")
.clone();
let _ = match vm.globals.intern_symbol(&x_str) {
Ok(s) => s,
Err(_) => return Err(VmErrorReason::UnexpectedVmState),
};
}
_ => {}
}
}
Ok(())
}

fn compiled_code_object_to_runtime_code_object(
vm: &mut VirtualMachine,
cm: &CompiledModule,
cco: aria_compiler::constant_value::CompiledCodeObject,
) -> Result<crate::runtime_value::runtime_code_object::CodeObject, VmErrorReason> {
let mut ops = byte_array_to_opcode_array(cco.body.as_slice())?;
replace_attribute_access_with_interned(vm, cm, &mut ops)?;
let body: Rc<[Opcode]> = ops.into();

Ok(crate::runtime_value::runtime_code_object::CodeObject {
name: cco.name.clone(),
body,
required_argc: cco.required_argc,
default_argc: cco.default_argc,
frame_size: cco.frame_size,
loc: cco.loc.clone(),
line_table: Rc::from(cco.line_table.clone()),
})
}

fn compiled_constant_to_runtime_value(
vm: &mut VirtualMachine,
cm: &CompiledModule,
value: aria_compiler::constant_value::ConstantValue,
) -> Result<RuntimeValue, VmErrorReason> {
use aria_compiler::constant_value::ConstantValue::{
CompiledCodeObject, Float, Integer, String,
};
match value {
Integer(n) => Ok(RuntimeValue::Integer(From::from(n))),
String(s) => Ok(RuntimeValue::String(s.into())),
CompiledCodeObject(cco) => Ok(RuntimeValue::CodeObject(
compiled_code_object_to_runtime_code_object(vm, cm, cco)?,
)),
Float(f) => Ok(RuntimeValue::Float(f.raw_value().into())),
}
}

impl RuntimeModuleImpl {
fn new(cm: CompiledModule) -> Result<Self, DecodeError> {
fn new(vm: &mut VirtualMachine, cm: CompiledModule) -> Result<Self, VmErrorReason> {
let entry_co =
compiled_code_object_to_runtime_code_object(vm, &cm, cm.load_entry_code_object())?;

let mut this = Self {
compiled_module: cm,
indexed_constants: Vec::new(),
values: Default::default(),
entry_co,
};

let mut i = 0;
Expand All @@ -41,7 +129,7 @@ impl RuntimeModuleImpl {
.load_indexed_const(i as u16)
.expect("module has missing constant data");

let r = RuntimeValue::try_from(&c)?;
let r = compiled_constant_to_runtime_value(vm, &this.compiled_module, c)?;
this.indexed_constants.push(r);

i += 1;
Expand Down Expand Up @@ -128,12 +216,16 @@ pub struct RuntimeModule {
}

impl RuntimeModule {
pub fn new(cm: CompiledModule) -> Result<Self, VmErrorReason> {
pub fn new(vm: &mut VirtualMachine, cm: CompiledModule) -> Result<Self, VmErrorReason> {
Ok(Self {
imp: Rc::new(RuntimeModuleImpl::new(cm)?),
imp: Rc::new(RuntimeModuleImpl::new(vm, cm)?),
})
}

pub fn load_entry_code_object(&self) -> &crate::runtime_value::runtime_code_object::CodeObject {
&self.imp.entry_co
}

pub(crate) fn named_values_of_this(&self) -> Vec<(String, NamedValue)> {
self.imp.named_values_of_this()
}
Expand Down
48 changes: 48 additions & 0 deletions vm-lib/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// SPDX-License-Identifier: Apache-2.0
use rustc_data_structures::fx::FxHashMap;
use thiserror::Error;

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Symbol(pub u32);

impl std::fmt::Display for Symbol {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Symbol({})", self.0)
}
}

#[derive(Default)]
pub struct Interner {
map: FxHashMap<String, Symbol>,
strings: Vec<String>,
}

#[derive(Clone, Error, PartialEq, Eq, Debug)]
pub enum InternError {
#[error("too many symbols have been interned")]
TooManySymbols,
}

impl Interner {
pub fn intern(&mut self, s: &str) -> Result<Symbol, InternError> {
if let Some(&sym) = self.map.get(s) {
return Ok(sym);
}

let id = self.strings.len();
if id >= u32::MAX as usize {
return Err(InternError::TooManySymbols);
}

let s = s.to_string();

let sym = Symbol(id as u32);
self.strings.push(s.clone());
self.map.insert(s, sym);
Ok(sym)
}

pub fn resolve(&self, sym: Symbol) -> Option<&str> {
self.strings.get(sym.0 as usize).map(|s| s.as_str())
}
}
13 changes: 4 additions & 9 deletions vm-lib/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use crate::{
list::List,
mixin::Mixin,
object::Object,
runtime_code_object::CodeObject,
structure::Struct,
},
stack::Stack,
Expand Down Expand Up @@ -442,13 +441,8 @@ impl VirtualMachine {
self.modules.insert(name.to_owned(), r_mod.clone());
}

let entry_cm = r_mod.get_compiled_module();
let entry_cco = entry_cm.load_entry_code_object();
let entry_co = match CodeObject::try_from(&entry_cco) {
Ok(co) => co,
Err(err) => return Err(VmErrorReason::from(err).into()),
};
let entry_f = Function::from_code_object(&entry_co, 0, &r_mod);
let entry_co = r_mod.load_entry_code_object();
let entry_f = Function::from_code_object(entry_co, 0, &r_mod);
let mut entry_frame: Frame = Default::default();

let entry_result = entry_f.eval(0, &mut entry_frame, self, &Default::default(), true);
Expand All @@ -466,7 +460,8 @@ impl VirtualMachine {
name: &str,
entry_cm: CompiledModule,
) -> ExecutionResult<RunloopExit<ModuleLoadInfo>> {
self.load_into_module(name, RuntimeModule::new(entry_cm)?)
let r_mod = RuntimeModule::new(self, entry_cm)?;
self.load_into_module(name, r_mod)
}

pub fn get_module_by_name(&self, name: &str) -> Option<RuntimeModule> {
Expand Down