Compare commits

..

6 Commits

Author SHA1 Message Date
Jesse Brault
d09d945323 Experimenting with garbage collection algorithm. 2025-10-14 21:18:06 -05:00
Jesse Brault
34fae6ccca Resolve local variables. 2025-10-14 11:14:07 -05:00
Jesse Brault
dd249dd5bd Properly using dyn for better dispatch of gather methods. 2025-10-13 11:58:30 -05:00
Jesse Brault
6b206605c1 Various gathering and scope table. 2025-10-13 10:51:22 -05:00
Jesse Brault
b47dea9136 Remove mut on compilation unit params in name analysis. 2025-10-09 17:16:18 -05:00
Jesse Brault
2b5be6ca49 Change scope_ids table to use refs. 2025-10-09 17:14:22 -05:00
20 changed files with 961 additions and 420 deletions

View File

@ -16,7 +16,7 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
let child_ident = format_ident!("{}", node_child.node_kind().to_case(Case::Snake));
quote! {
#type_ident::#rule_ident(#child_ident) => vec![
#child_ident.as_node_ref()
#child_ident
]
}
}
@ -35,14 +35,14 @@ pub fn make_enum_ast_node_impl(enum_spec: &TreeEnumBuildSpec) -> TokenStream {
.collect::<Vec<_>>();
quote! {
impl AstNode for #type_ident {
fn children(&self) -> Vec<AstNodeRef> {
impl<'a> AstNode<'a> for #type_ident {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
match self {
#(#match_arms,)*
}
}
fn as_node_ref(&self) -> AstNodeRef {
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self)
}
}

View File

@ -1,16 +1,16 @@
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use crate::spec::leaf_enum_spec::LeafEnumBuildSpec;
pub fn make_leaf_enum_ast_node_impl(spec: &LeafEnumBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", spec.build());
quote! {
impl AstNode for #type_ident {
fn children(&self) -> Vec<AstNodeRef> {
impl<'a> AstNode<'a> for #type_ident {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
vec![]
}
fn as_node_ref(&self) -> AstNodeRef {
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self)
}
}

View File

@ -5,12 +5,12 @@ use quote::{format_ident, quote};
pub fn make_leaf_struct_ast_node_impl(spec: &LeafStructBuildSpec) -> TokenStream {
let type_ident = format_ident!("{}", spec.build());
quote! {
impl AstNode for #type_ident {
fn children(&self) -> Vec<AstNodeRef> {
impl<'a> AstNode<'a> for #type_ident {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
vec![]
}
fn as_node_ref(&self) -> AstNodeRef {
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self)
}
}

View File

@ -71,3 +71,34 @@ pub fn make_ast_enum_member(build_spec: &BuildSpec) -> Option<TokenStream> {
}
})
}
pub fn make_ast_node_ref_unwrapper(build_spec: &BuildSpec) -> Option<TokenStream> {
match build_spec {
BuildSpec::Enum(enum_spec) => {
Some(format_ident!("{}", enum_spec.build()))
}
BuildSpec::LeafEnum(leaf_enum) => {
Some(format_ident!("{}", leaf_enum.build()))
}
BuildSpec::Struct(struct_spec) => {
Some(format_ident!("{}", struct_spec.build()))
}
BuildSpec::LeafStruct(leaf_struct) => {
Some(format_ident!("{}", leaf_struct.build()))
}
BuildSpec::Production(_) => None,
BuildSpec::NodeProduction(_) => None,
BuildSpec::PolymorphicType(polymorphic_type) => {
Some(format_ident!("{}", polymorphic_type.name()))
}
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => {
Some(format_ident!("{}", polymorphic_enum_loop.name()))
}
BuildSpec::PolymorphicPassThrough(_) => None
}
.map(|type_ident| {
quote! {
AstNodeRef::#type_ident(inner) => *inner
}
})
}

View File

@ -28,20 +28,20 @@ pub fn make_polymorphic_enum_loop_ast_node_impl(
}
};
quote! {
children.push(self.#child_ident().as_node_ref())
children.push(self.#child_ident() as &dyn AstNode);
}
})
.collect::<Vec<_>>();
quote! {
impl AstNode for #type_ident {
fn children(&self) -> Vec<AstNodeRef> {
let mut children: Vec<AstNodeRef> = vec![];
impl<'a> AstNode<'a> for #type_ident {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
let mut children = vec![];
#(#child_adders;)*
children
}
fn as_node_ref(&self) -> AstNodeRef {
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self)
}
}

View File

@ -11,20 +11,20 @@ pub fn make_polymorphic_type_ast_node_impl(spec: &PolymorphicTypeBuildSpec) -> T
let variant_ident = format_ident!("{}", variant.name());
let child_ident = format_ident!("{}", variant.inner_kind().to_case(Case::Snake));
quote! {
#type_ident::#variant_ident(#child_ident) => vec![#child_ident.as_node_ref()]
#type_ident::#variant_ident(#child_ident) => vec![#child_ident]
}
})
.collect::<Vec<_>>();
quote! {
impl AstNode for #type_ident {
fn children(&self) -> Vec<AstNodeRef> {
impl<'a> AstNode<'a> for #type_ident {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
match self {
#(#match_arms,)*
}
}
fn as_node_ref(&self) -> AstNodeRef {
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self)
}
}

View File

@ -13,8 +13,8 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
VecChildBuild::Node(_) => {
let child_ident = format_ident!("{}", vec_child.name());
let children_stream = quote! {
for child in self.#child_ident().map(AstNode::as_node_ref) {
children.push(child);
for child in self.#child_ident() {
children.push(child as &dyn AstNode);
}
};
Some(children_stream)
@ -26,12 +26,12 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
if member_child.optional() {
Some(quote! {
if let Some(#child_ident) = self.#child_ident() {
children.push(#child_ident.as_node_ref());
children.push(#child_ident as &dyn AstNode);
}
})
} else {
Some(quote! {
children.push(self.#child_ident().as_node_ref())
children.push(self.#child_ident() as &dyn AstNode)
})
}
}
@ -44,14 +44,14 @@ pub fn make_struct_ast_node_impl(spec: &StructSpec) -> TokenStream {
.collect::<Vec<_>>();
quote! {
impl AstNode for #type_ident {
fn children(&self) -> Vec<AstNodeRef> {
let mut children: Vec<AstNodeRef> = vec![];
impl<'a> AstNode<'a> for #type_ident {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>> {
let mut children = vec![];
#(#child_adders;)*
children
}
fn as_node_ref(&self) -> AstNodeRef {
fn as_node_ref(&'a self) -> AstNodeRef<'a> {
AstNodeRef::#type_ident(&self)
}
}

View File

@ -6,7 +6,7 @@ mod spec;
mod type_gen;
mod walk;
use crate::ast_node::{make_ast_enum_member, make_ast_node_impl};
use crate::ast_node::{make_ast_enum_member, make_ast_node_impl, make_ast_node_ref_unwrapper};
use crate::build_fn::make_build_fn;
use crate::deserialize::deserialize_yaml_spec;
use crate::pretty_print::make_pretty_print_impl;
@ -165,6 +165,13 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
.map(Option::unwrap)
.collect::<Vec<_>>();
let inner_unwrappers = build_specs
.iter()
.map(|build_spec| make_ast_node_ref_unwrapper(build_spec))
.filter(Option::is_some)
.map(Option::unwrap)
.collect::<Vec<_>>();
let combined = quote! {
use crate::ast::node::*;
@ -172,10 +179,18 @@ fn generate_ast_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
#(#ast_enum_members,)*
}
pub trait AstNode {
fn children(&self) -> Vec<AstNodeRef>;
impl<'a> AstNodeRef<'a> {
pub fn inner(&self) -> &dyn AstNode<'a> {
match self {
#(#inner_unwrappers,)*
}
}
}
fn as_node_ref(&self) -> AstNodeRef;
pub trait AstNode<'a> {
fn children(&'a self) -> Vec<&'a dyn AstNode<'a>>;
fn as_node_ref(&'a self) -> AstNodeRef<'a>;
}
#(#impls)*

View File

@ -1,59 +1,16 @@
use crate::spec::BuildSpec;
use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use quote::quote;
pub fn make_walk_fn(specs: &[BuildSpec]) -> TokenStream {
let child_match_arms = specs
.iter()
.map(|spec| match spec {
BuildSpec::Enum(enum_spec) => Some((
format_ident!("{}", enum_spec.build()),
format_ident!("{}", enum_spec.build().to_case(Case::Snake)),
)),
BuildSpec::LeafEnum(leaf_enum) => Some((
format_ident!("{}", leaf_enum.build()),
format_ident!("{}", leaf_enum.build().to_case(Case::Snake)),
)),
BuildSpec::Struct(struct_spec) => Some((
format_ident!("{}", struct_spec.build()),
format_ident!("{}", struct_spec.build().to_case(Case::Snake)),
)),
BuildSpec::LeafStruct(leaf_struct) => Some((
format_ident!("{}", leaf_struct.build()),
format_ident!("{}", leaf_struct.build().to_case(Case::Snake)),
)),
BuildSpec::Production(_) => None,
BuildSpec::NodeProduction(_) => None,
BuildSpec::PolymorphicType(polymorphic_type) => Some((
format_ident!("{}", polymorphic_type.name()),
format_ident!("{}", polymorphic_type.name().to_case(Case::Snake)),
)),
BuildSpec::PolymorphicEnumLoop(polymorphic_enum_loop) => Some((
format_ident!("{}", polymorphic_enum_loop.name()),
format_ident!("{}", polymorphic_enum_loop.name().to_case(Case::Snake)),
)),
BuildSpec::PolymorphicPassThrough(_) => None,
})
.filter(Option::is_some)
.map(Option::unwrap)
.map(|(type_ident, inner_ident)| {
quote! {
#type_ident(#inner_ident) => walk_depth_first(#inner_ident, f)
}
})
.collect::<Vec<_>>();
quote! {
use crate::ast::node::*;
use crate::ast::ast_node::*;
pub fn walk_depth_first(node: &impl AstNode, f: &mut impl FnMut(AstNodeRef)) {
pub fn walk_depth_first<'a>(node: &'a dyn AstNode<'a>, f: &mut impl FnMut(AstNodeRef<'a>)) {
use AstNodeRef::*;
for child in node.children() {
match child {
#(#child_match_arms,)*
}
walk_depth_first(child, f);
}
f(node.as_node_ref());
}

View File

@ -7,8 +7,8 @@ fn getWorlds() -> List<World> = [
]
fn findWorldByColor(worlds: List<World>, color: String) -> String
worlds.find { it.color == color }
.map { it.name }
worlds.find { it -> it.color == color }
.map { it -> it.name }
.expect "No world has the given color ${color}"
end

View File

@ -31,7 +31,7 @@ pub fn name_analysis(paths: &Vec<PathBuf>) -> Result<(), Box<dyn std::error::Err
let mut symbol_table = SymbolTable::new();
add_std_core_symbols(&mut symbol_table).expect("Failed to add std::core symbols.");
let diagnostics = analyze_names(compilation_units.as_mut_slice(), &files, &mut symbol_table);
let diagnostics = analyze_names(&compilation_units, &files, &mut symbol_table);
if diagnostics.is_empty() {
println!("Name analysis complete.");
println!("{}", symbol_table);

File diff suppressed because it is too large Load Diff

View File

@ -19,42 +19,46 @@ The resolve phase has one main responsibility: resolve all references based on t
`scope_id` property.
*/
use crate::ast::node::{CompilationUnit, VariableUse};
// use crate::name_analysis::resolve::resolve_compilation_unit;
use crate::ast::ast_node::AstNode;
use crate::ast::node::CompilationUnit;
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::gather::gather_compilation_unit;
// use crate::name_analysis::resolve::resolve_compilation_unit;
use crate::name_analysis::symbol_table::SymbolTable;
use codespan_reporting::files::Files;
use std::collections::HashMap;
use std::hash::Hash;
use crate::name_analysis::scope_table::ScopeTable;
pub(self) mod fqn_context;
mod gather;
// mod resolve;
pub mod symbol;
pub mod symbol_table;
mod scope_table;
pub fn analyze_names<'a, F: Files<'a, FileId = usize, Name = String>>(
compilation_units: &mut [Box<CompilationUnit>],
compilation_units: &[Box<CompilationUnit>],
files: &'a F,
symbol_table: &mut SymbolTable,
) -> Vec<DmDiagnostic> {
let mut diagnostics = vec![];
let mut scope_ids: HashMap<VariableUse, usize> = HashMap::new();
let mut scope_table = ScopeTable::new();
// gather symbols
for compilation_unit in compilation_units.iter_mut() {
for compilation_unit in compilation_units {
let file_name = files.name(compilation_unit.file_id()).unwrap();
gather_compilation_unit(
compilation_unit,
&file_name,
symbol_table,
&mut scope_ids,
&mut scope_table,
&mut diagnostics,
);
}
// resolve symbols
for compilation_unit in compilation_units.iter_mut() {
for compilation_unit in compilation_units {
// resolve_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
}

View File

@ -0,0 +1,32 @@
use crate::ast::node::{FullyQualifiedName, VariableUse};
use std::collections::HashMap;
pub struct ScopeTable<'a> {
variable_use_scopes: HashMap<&'a VariableUse, usize>,
fqn_scopes: HashMap<&'a FullyQualifiedName, usize>,
}
impl<'a> ScopeTable<'a> {
pub fn new() -> Self {
Self {
variable_use_scopes: HashMap::new(),
fqn_scopes: HashMap::new(),
}
}
pub fn insert_variable_use_scope(&mut self, variable_use: &'a VariableUse, scope_id: usize) {
self.variable_use_scopes.insert(variable_use, scope_id);
}
pub fn insert_fqn_scope(&mut self, fqn: &'a FullyQualifiedName, scope_id: usize) {
self.fqn_scopes.insert(fqn, scope_id);
}
pub fn variable_use_scope(&self, variable_use: &'a VariableUse) -> Option<usize> {
self.variable_use_scopes.get(&variable_use).copied()
}
pub fn fqn_scope(&self, fqn: &'a FullyQualifiedName) -> Option<usize> {
self.fqn_scopes.get(&fqn).copied()
}
}

View File

@ -45,8 +45,11 @@ impl SymbolTable {
pub fn push_scope(&mut self, debug_name: &str) {
let id = self.scopes.len();
self.scopes
.push(Scope::new(Some(self.current_scope_id), id, debug_name.to_string()));
self.scopes.push(Scope::new(
Some(self.current_scope_id),
id,
debug_name.to_string(),
));
self.current_scope_id = id;
}
@ -316,7 +319,61 @@ impl SymbolTable {
Some(&self.scopes[parent_id])
} else {
None
};
}
Err(NoDefinition)
}
fn lookup_addressable_in_scope_by_identifier(
scope: &Scope,
identifier: &str,
) -> Option<Symbol> {
scope
.variable_symbols()
.get(identifier)
.map(|variable_symbol| Symbol::Variable(variable_symbol.clone()))
.or_else(|| {
scope
.parameter_symbols()
.get(identifier)
.map(|parameter_symbol| Symbol::Parameter(parameter_symbol.clone()))
})
.or_else(|| {
scope
.class_member_symbols()
.get(identifier)
.map(|class_member_symbol| Symbol::ClassMember(class_member_symbol.clone()))
})
.or_else(|| {
scope
.function_symbols()
.get(identifier)
.map(|function_symbol| Symbol::Function(function_symbol.clone()))
})
.or_else(|| {
scope
.type_symbols()
.get(identifier)
.map(|type_symbol| Symbol::Type(type_symbol.clone()))
})
}
pub fn lookup_addressable_by_identifier(
&self,
identifier: &str,
scope_id: usize,
) -> Result<Symbol, SymbolLookupError> {
let mut scope_opt = Some(&self.scopes[scope_id]);
while let Some(scope) = scope_opt {
if let Some(symbol) = Self::lookup_addressable_in_scope_by_identifier(scope, identifier)
{
return Ok(symbol);
}
scope_opt = if let Some(parent_id) = scope.parent() {
Some(&self.scopes[parent_id])
} else {
None
};
}
Err(NoDefinition)
}

View File

@ -50,7 +50,6 @@ Identifier:
- range:
kind: range
derive:
- Clone
- PartialEq
- Eq
- Hash
@ -60,6 +59,10 @@ FullyQualifiedName:
- identifiers:
vec:
rule: Identifier
derive:
- PartialEq
- Eq
- Hash
# Lists
TypeUseList:
@ -74,7 +77,7 @@ IdentifierList:
- identifiers:
vec:
rule: Identifier
ParenthesesOptionalTypeUseList:
ParenthesesTypeUseList:
struct:
children:
- type_use_list:
@ -90,19 +93,29 @@ TypeUse:
- TupleTypeUse
- FunctionTypeUse
PrimitiveType:
leaf_enum:
tree_enum:
rules:
- Byte
- Short
- Char
- Int
- Long
- Double
- Bool
- String
- Byte:
child: false
- Short:
child: false
- Char:
child: false
- Int:
child: false
- Long:
child: false
- Double:
child: false
- Bool:
child: false
- String:
child: false
- TypedArray
- Any
- Void
- Any:
child: false
- Void:
child: false
TypedArray:
struct:
children:
@ -160,7 +173,7 @@ GenericParameters:
TupleArguments:
struct:
children:
- parentheses_optional_type_use_list
- parentheses_type_use_list
# Implements List
ImplementsList:
@ -656,7 +669,7 @@ IfClause:
skip:
rule: Then
- statements:
skip:
vec:
rule: Statement
IfElseIf:
struct:
@ -704,7 +717,7 @@ ForStatement:
- do_kw:
skip:
rule: Do
- statement:
- statements:
vec:
rule: Statement
- end_kw:
@ -731,7 +744,6 @@ VariableUse:
children:
- identifier
derive:
- Clone
- PartialEq
- Eq
- Hash

View File

@ -199,7 +199,7 @@ IdentifierList = {
~ ( "," ~ Identifier )*
}
ParenthesesOptionalTypeUseList = {
ParenthesesTypeUseList = {
"("
~ TypeUseList?
~ ")"
@ -272,7 +272,7 @@ GenericParameters = {
// Tuple Arguments
TupleArguments = {
ParenthesesOptionalTypeUseList
ParenthesesTypeUseList
}
// Implements list

205
src/vm/mem/mod.rs Normal file
View File

@ -0,0 +1,205 @@
use std::cell::RefCell;
use std::marker::PhantomData;
use std::ops::Mul;
#[derive(Debug)]
pub struct Gc<T> {
inner: *mut GcInner,
data: *const T,
_phantom: PhantomData<T>,
}
#[derive(Debug)]
pub struct GcInner {
color: GcColor,
size: usize,
}
impl GcInner {
pub fn new(size: usize) -> Self {
Self {
color: GcColor::White,
size,
}
}
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum GcColor {
White,
Black,
}
impl<T> Gc<T> {
pub fn new(data: T) -> Self {
let inner = Box::into_raw(Box::new(GcInner::new(size_of::<T>())));
let boxed_data = Box::into_raw(Box::new(data)) as *const T;
Self {
inner,
data: boxed_data,
_phantom: PhantomData,
}
}
pub fn set_color(&mut self, color: GcColor) {
unsafe {
(*self.inner).color = color;
}
}
pub fn color(&self) -> GcColor {
unsafe { (*self.inner).color }
}
pub fn size(&self) -> usize {
unsafe { (*self.inner).size }
}
pub fn data(&self) -> &T {
unsafe { &*self.data }
}
pub fn dealloc(&mut self) {
unsafe {
drop(Box::from_raw(self.inner));
drop(Box::from_raw(self.data as *mut T));
}
}
}
impl<T> Clone for Gc<T> {
fn clone(&self) -> Self {
Self {
inner: self.inner,
data: self.data,
_phantom: PhantomData,
}
}
}
#[derive(Debug)]
enum DvmValue {
Primitive(usize),
Object(Gc<RefCell<DvmObject>>),
Nil,
}
#[derive(Debug)]
struct DvmObject {
fields: Vec<DvmValue>,
}
impl DvmObject {
pub fn new() -> Self {
Self { fields: vec![] }
}
pub fn fields(&self) -> &[DvmValue] {
&self.fields
}
pub fn fields_mut(&mut self) -> &mut Vec<DvmValue> {
&mut self.fields
}
}
fn collect_garbage(
next_gc: &mut usize,
current_size: &mut usize,
stack: &Vec<DvmValue>,
gcs: &mut Vec<Gc<RefCell<DvmObject>>>,
) {
let mut gray_stack: Vec<Gc<RefCell<DvmObject>>> = vec![];
for stack_value in stack {
match stack_value {
DvmValue::Object(gc) => {
if gc.color() == GcColor::White {
gray_stack.push(gc.clone());
}
}
_ => {}
}
}
while let Some(mut current) = gray_stack.pop() {
for field in current.data().borrow().fields() {
match field {
DvmValue::Object(object) => {
gray_stack.push(object.clone());
}
_ => {}
}
}
current.set_color(GcColor::Black);
}
let mut collected_size: usize = 0;
for i in (0..gcs.len()).rev() {
if gcs[i].color() == GcColor::White {
let mut gc = gcs.remove(i);
let size = gc.size();
*current_size -= size;
collected_size += size;
gc.dealloc();
} else {
gcs[i].set_color(GcColor::White);
}
}
*next_gc = std::cmp::max(1024 * 1024, current_size.mul(2));
println!(
"collected_size: {}, current_size: {}, next_gc: {}",
collected_size, current_size, next_gc
);
}
fn maybe_collect_garbage(
next_gc: &mut usize,
current_size: &mut usize,
stack: &Vec<DvmValue>,
gcs: &mut Vec<Gc<RefCell<DvmObject>>>,
) {
if current_size > next_gc {
collect_garbage(next_gc, current_size, stack, gcs);
}
}
fn alloc_dvm_object(
next_gc: &mut usize,
current_size: &mut usize,
stack: &Vec<DvmValue>,
gcs: &mut Vec<Gc<RefCell<DvmObject>>>,
) -> Gc<RefCell<DvmObject>> {
maybe_collect_garbage(next_gc, current_size, stack, gcs);
let mut object = DvmObject::new();
object.fields_mut().push(DvmValue::Nil);
let gc = Gc::new(RefCell::new(object));
*current_size += gc.size();
gcs.push(gc.clone());
gc
}
fn set_field(obj: &mut Gc<RefCell<DvmObject>>, field_index: usize, value: DvmValue) {
let mut binding = obj.data().borrow_mut();
binding.fields_mut()[field_index] = value;
}
#[cfg(test)]
mod tests {
use crate::vm::mem::{alloc_dvm_object, collect_garbage, DvmObject, DvmValue, Gc};
use std::cell::RefCell;
#[test]
fn test() {
let mut stack: Vec<DvmValue> = vec![];
let mut heap: Vec<Gc<RefCell<DvmObject>>> = vec![];
let mut next_gc: usize = 1024 * 1024;
let mut current_size: usize = 0;
for i in 0..100_000_000 {
let mut o = alloc_dvm_object(&mut next_gc, &mut current_size, &stack, &mut heap);
}
collect_garbage(&mut next_gc, &mut current_size, &stack, &mut heap);
}
}

View File

@ -6,6 +6,7 @@ pub mod implementation;
pub mod instruction;
pub mod interface;
pub mod lib;
mod mem;
pub mod method;
pub mod object;
pub mod op_codes;