From 91014e8ebc17d192da07cbbc1337341ed18173d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Inf=C3=BChr?= Date: Thu, 5 Dec 2024 22:16:53 +0100 Subject: [PATCH] runtime: Make more use of vtable instead of class instance --- dora-runtime/src/boots.rs | 40 +++----- dora-runtime/src/cannon/asm.rs | 26 ++---- dora-runtime/src/cannon/codegen.rs | 141 +++++++++-------------------- dora-runtime/src/size.rs | 2 +- dora-runtime/src/vm.rs | 14 ++- dora-runtime/src/vm/classes.rs | 12 ++- dora-runtime/src/vm/initialize.rs | 32 +++---- dora-runtime/src/vm/known.rs | 50 +++++----- dora-runtime/src/vm/specialize.rs | 48 ++++------ 9 files changed, 140 insertions(+), 225 deletions(-) diff --git a/dora-runtime/src/boots.rs b/dora-runtime/src/boots.rs index 3dbf5cacc..65124f0f5 100644 --- a/dora-runtime/src/boots.rs +++ b/dora-runtime/src/boots.rs @@ -17,8 +17,8 @@ use crate::size::InstanceSize; use crate::threads::current_thread; use crate::vm::compute_vtable_index; use crate::vm::{ - create_class_instance, create_enum_instance, ensure_class_instance_for_enum_variant, get_vm, - impls, CodeDescriptor, FctImplementation, VM, + create_enum_instance, ensure_class_instance_for_enum_variant, get_vm, impls, CodeDescriptor, + FctImplementation, VM, }; use self::deserializer::{decode_bytecode_type, decode_bytecode_type_array}; @@ -211,7 +211,7 @@ extern "C" fn get_class_pointer_for_lambda(data: Handle) -> Address let id = crate::vm::ensure_class_instance_for_lambda(vm, fct_id, type_params); let cls = vm.class_instances.idx(id); - cls.vtblptr() + cls.vtable_address() } extern "C" fn get_class_pointer_for_trait_object_raw(data: Handle) -> Address { @@ -234,7 +234,7 @@ extern "C" fn get_class_pointer_for_trait_object_raw(data: Handle) - let id = crate::vm::ensure_class_instance_for_trait_object(vm, trait_ty, actual_object_ty); let cls = vm.class_instances.idx(id); - cls.vtblptr() + cls.vtable_address() } extern "C" fn get_class_size_for_trait_object_raw(data: Handle) -> i32 { @@ -312,13 +312,8 @@ extern "C" fn get_class_size(data: Handle) -> u32 { } fn get_class_size_raw(vm: &VM, cls_id: ClassId, type_params: BytecodeTypeArray) -> u32 { - let class_instance_id = create_class_instance(vm, cls_id, &type_params); - let cls = vm.class_instances.idx(class_instance_id); - - match cls.size { - InstanceSize::Fixed(size) => size as u32, - _ => unreachable!(), - } + let vtable = vm.vtable_for_class(cls_id, &type_params); + vtable.instance_size() as u32 } fn get_element_size_raw(data: Handle) -> u32 { @@ -339,16 +334,8 @@ fn get_element_size_raw(data: Handle) -> u32 { let type_params = decode_bytecode_type_array(&mut reader); assert!(!reader.has_more()); - let class_instance_id = create_class_instance(vm, cls_id, &type_params); - let cls = vm.class_instances.idx(class_instance_id); - - match cls.size { - InstanceSize::StructArray(element_size) => element_size as u32, - InstanceSize::ObjArray => crate::mem::ptr_width() as u32, - InstanceSize::PrimitiveArray(element_size) => element_size as u32, - InstanceSize::UnitArray => 0, - _ => unreachable!(), - } + let vtable = vm.vtable_for_class(cls_id, &type_params); + vtable.element_size() as u32 } extern "C" fn get_class_pointer(data: Handle) -> Address { @@ -373,9 +360,7 @@ extern "C" fn get_class_pointer(data: Handle) -> Address { } fn get_class_pointer_raw(vm: &VM, cls_id: ClassId, type_params: BytecodeTypeArray) -> Address { - let class_instance_id = create_class_instance(vm, cls_id, &type_params); - let cls = vm.class_instances.idx(class_instance_id); - cls.vtblptr() + vm.vtable_for_class(cls_id, &type_params).address() } extern "C" fn get_field_offset(data: Handle) -> u32 { @@ -406,9 +391,8 @@ fn get_field_offset_raw( type_params: BytecodeTypeArray, field_id: u32, ) -> u32 { - let class_instance_id = create_class_instance(vm, cls_id, &type_params); - let cls = vm.class_instances.idx(class_instance_id); - let field = &cls.fields[field_id as usize]; + let vtable = vm.vtable_for_class(cls_id, &type_params); + let field = &vtable.fields[field_id as usize]; field.offset.try_into().expect("overflow") } @@ -545,7 +529,7 @@ extern "C" fn get_class_data_for_enum_variant_raw(data: Handle) -> R }; let mut buffer = ByteBuffer::new(); - buffer.emit_address(cls.vtblptr()); + buffer.emit_address(cls.vtable_address()); buffer.emit_u32(alloc_size as u32); byte_array_from_buffer(vm, buffer.data()).cast() } diff --git a/dora-runtime/src/cannon/asm.rs b/dora-runtime/src/cannon/asm.rs index 10612b3c6..514da4242 100644 --- a/dora-runtime/src/cannon/asm.rs +++ b/dora-runtime/src/cannon/asm.rs @@ -12,12 +12,12 @@ use crate::gc::Address; use crate::masm::{CondCode, Label, MacroAssembler, Mem, ScratchReg}; use crate::mirror::Header; use crate::mode::MachineMode; -use crate::size::InstanceSize; use crate::threads::ThreadLocalData; use crate::vm::{ - create_enum_instance, create_struct_instance, get_concrete_tuple_bty_array, ClassInstance, - CodeDescriptor, EnumLayout, GcPoint, LazyCompilationSite, Trap, INITIALIZED, VM, + create_enum_instance, create_struct_instance, get_concrete_tuple_bty_array, CodeDescriptor, + EnumLayout, GcPoint, LazyCompilationSite, Trap, INITIALIZED, VM, }; +use crate::VTable; use dora_bytecode::{BytecodeType, BytecodeTypeArray, FunctionId, GlobalId, Location, StructId}; pub struct BaselineAssembler<'a> { @@ -1098,18 +1098,14 @@ impl<'a> BaselineAssembler<'a> { )); } - pub fn initialize_object(&mut self, obj: Reg, class_instance: &ClassInstance) { - let size = match class_instance.size { - InstanceSize::Fixed(size) => size, - _ => unreachable!(), - }; - + pub fn initialize_object(&mut self, obj: Reg, vtable: &VTable) { + let size = vtable.instance_size(); let tmp_reg = self.get_scratch(); // Store classptr/vtable in object. let (is_marked, is_remembered) = self.vm.gc.initial_metadata_value(size as usize, false); let header_word_value = Header::compute_header_word( - class_instance.vtblptr(), + vtable.address(), self.vm.meta_space_start(), is_marked, is_remembered, @@ -1134,7 +1130,7 @@ impl<'a> BaselineAssembler<'a> { pub fn initialize_array_header( &mut self, obj: Reg, - class_instance: &ClassInstance, + vtable: &VTable, length_reg: Reg, size_reg: Reg, ) { @@ -1142,12 +1138,8 @@ impl<'a> BaselineAssembler<'a> { assert!(obj != length_reg && length_reg != *tmp_reg && obj != *tmp_reg); // store classptr in object - let header_word_value = Header::compute_header_word( - class_instance.vtblptr(), - self.vm.meta_space_start(), - false, - false, - ); + let header_word_value = + Header::compute_header_word(vtable.address(), self.vm.meta_space_start(), false, false); self.masm.load_int_const( MachineMode::IntPtr, diff --git a/dora-runtime/src/cannon/codegen.rs b/dora-runtime/src/cannon/codegen.rs index 758287323..1258ffabb 100644 --- a/dora-runtime/src/cannon/codegen.rs +++ b/dora-runtime/src/cannon/codegen.rs @@ -15,9 +15,8 @@ use crate::masm::{CondCode, Label, Mem}; use crate::mem::{self, align_i32}; use crate::mirror::{Header, Str}; use crate::mode::MachineMode; -use crate::size::InstanceSize; use crate::vm::{ - compute_vtable_index, create_class_instance, create_enum_instance, create_struct_instance, + compute_vtable_index, create_enum_instance, create_struct_instance, ensure_class_instance_for_enum_variant, ensure_class_instance_for_lambda, ensure_class_instance_for_trait_object, find_trait_impl, get_concrete_tuple_bty, get_concrete_tuple_bty_array, specialize_bty, specialize_bty_array, @@ -1324,21 +1323,19 @@ impl<'a> CannonCodeGen<'a> { fn emit_load_field(&mut self, dest: Register, obj: Register, field_idx: ConstPoolIdx) { assert!(self.bytecode.register_type(obj).is_ptr()); - let (class_instance_id, field_id) = match self.bytecode.const_pool(field_idx) { + let (vtable, field_id) = match self.bytecode.const_pool(field_idx) { ConstPoolEntry::Field(cls_id, type_params, field_id) => { let type_params = self.specialize_bty_array(&type_params); debug_assert!(type_params.iter().all(|ty| ty.is_concrete_type())); - let class_instance_id = create_class_instance(self.vm, *cls_id, &type_params); + let vtable = self.vm.vtable_for_class(*cls_id, &type_params); - (class_instance_id, *field_id) + (vtable, *field_id) } _ => unreachable!(), }; - let cls = self.vm.class_instances.idx(class_instance_id); - - let field = &cls.fields[field_id as usize]; + let field = &vtable.fields[field_id as usize]; let obj_reg = REG_TMP1; self.emit_load_register(obj, obj_reg.into()); @@ -1366,10 +1363,8 @@ impl<'a> CannonCodeGen<'a> { let type_params = self.specialize_bty_array(&type_params); debug_assert!(type_params.iter().all(|ty| ty.is_concrete_type())); - let class_instance_id = create_class_instance(self.vm, cls_id, &type_params); - let cls = self.vm.class_instances.idx(class_instance_id); - - let field = &cls.fields[field_id as usize]; + let vtable = self.vm.vtable_for_class(cls_id, &type_params); + let field = &vtable.fields[field_id as usize]; assert!(self.bytecode.register_type(obj).is_ptr()); let obj_reg = REG_TMP1; @@ -1776,16 +1771,9 @@ impl<'a> CannonCodeGen<'a> { let type_params = self.specialize_bty_array(&type_params); debug_assert!(type_params.iter().all(|ty| ty.is_concrete_type())); - let class_instance_id = create_class_instance(self.vm, cls_id, &type_params); - let class_instance = self.vm.class_instances.idx(class_instance_id); - - let alloc_size = match class_instance.size { - InstanceSize::Fixed(size) => AllocationSize::Fixed(size as usize), - _ => unreachable!( - "class size type {:?} for new object not supported", - class_instance.size - ), - }; + let vtable = self.vm.vtable_for_class(cls_id, &type_params); + let alloc_size = vtable.instance_size(); + let alloc_size = AllocationSize::Fixed(alloc_size); let gcpoint = self.create_gcpoint(); let position = self.bytecode.offset_location(self.current_offset.to_u32()); @@ -1795,7 +1783,7 @@ impl<'a> CannonCodeGen<'a> { // store gc object in temporary storage self.emit_store_register(REG_RESULT.into(), dest); - self.asm.initialize_object(REG_RESULT, &*class_instance); + self.asm.initialize_object(REG_RESULT, vtable); } fn emit_new_object_initialized(&mut self, dest: Register, idx: ConstPoolIdx) { @@ -1813,16 +1801,10 @@ impl<'a> CannonCodeGen<'a> { let type_params = self.specialize_bty_array(&type_params); debug_assert!(type_params.iter().all(|ty| ty.is_concrete_type())); - let class_instance_id = create_class_instance(self.vm, cls_id, &type_params); - let class_instance = self.vm.class_instances.idx(class_instance_id); + let vtable = self.vm.vtable_for_class(cls_id, &type_params); - let alloc_size = match class_instance.size { - InstanceSize::Fixed(size) => AllocationSize::Fixed(size as usize), - _ => unreachable!( - "class size type {:?} for new object not supported", - class_instance.size - ), - }; + let alloc_size = vtable.instance_size(); + let alloc_size = AllocationSize::Fixed(alloc_size); let gcpoint = self.create_gcpoint(); let position = self.bytecode.offset_location(self.current_offset.to_u32()); @@ -1832,15 +1814,15 @@ impl<'a> CannonCodeGen<'a> { // store gc object in temporary storage self.emit_store_register(REG_RESULT.into(), dest); - self.asm.initialize_object(REG_RESULT, &*class_instance); + self.asm.initialize_object(REG_RESULT, vtable); let obj_reg = REG_TMP1; self.emit_load_register(dest, obj_reg.into()); - assert_eq!(arguments.len(), class_instance.fields.len()); + assert_eq!(arguments.len(), vtable.fields.len()); // Initialize all class fields. - for (&argument, field) in arguments.iter().zip(class_instance.fields.iter()) { + for (&argument, field) in arguments.iter().zip(vtable.fields.iter()) { let ty = self.specialize_register_type(argument); let argument = self.reg(argument); self.asm.store_field(obj_reg, field.offset, argument, ty); @@ -1860,8 +1842,7 @@ impl<'a> CannonCodeGen<'a> { let type_params = self.specialize_bty_array(&type_params); - let class_instance_id = create_class_instance(self.vm, cls_id, &type_params); - let class_instance = self.vm.class_instances.idx(class_instance_id); + let vtable = self.vm.vtable_for_class(cls_id, &type_params); let length_reg = REG_TMP1; let size_reg = REG_TMP2; @@ -1869,23 +1850,13 @@ impl<'a> CannonCodeGen<'a> { let array_header_size = Header::size() as usize + mem::ptr_width_usize(); - let alloc_size = match class_instance.size { - InstanceSize::PrimitiveArray(size) | InstanceSize::StructArray(size) => { - assert_ne!(size, 0); - self.asm - .determine_array_size(size_reg, length_reg, size, true); - AllocationSize::Dynamic(size_reg) - } - InstanceSize::ObjArray => { - self.asm - .determine_array_size(size_reg, length_reg, mem::ptr_width(), true); - AllocationSize::Dynamic(size_reg) - } - InstanceSize::UnitArray => AllocationSize::Fixed(array_header_size), - _ => unreachable!( - "class size type {:?} for new array not supported", - class_instance.size - ), + let element_size = vtable.element_size(); + let alloc_size = if element_size > 0 { + self.asm + .determine_array_size(size_reg, length_reg, element_size as i32, true); + AllocationSize::Dynamic(size_reg) + } else { + AllocationSize::Fixed(array_header_size) }; // REG_TMP1 and REG_TMP2 should be restored in the slow path of the allocation. @@ -1901,17 +1872,10 @@ impl<'a> CannonCodeGen<'a> { self.emit_store_register(REG_RESULT.into(), dest); self.asm - .initialize_array_header(REG_RESULT, &*class_instance, length_reg, size_reg); + .initialize_array_header(REG_RESULT, vtable, length_reg, size_reg); - match class_instance.size { - InstanceSize::PrimitiveArray(size) | InstanceSize::StructArray(size) => { - self.emit_array_initialization(REG_RESULT, length_reg, size); - } - InstanceSize::ObjArray => { - self.emit_array_initialization(REG_RESULT, length_reg, mem::ptr_width()); - } - InstanceSize::UnitArray => {} - _ => unreachable!(), + if element_size > 0 { + self.emit_array_initialization(REG_RESULT, length_reg, element_size as i32); } } @@ -2008,16 +1972,8 @@ impl<'a> CannonCodeGen<'a> { &*enum_, variant_idx, ); - - let cls = self.vm.class_instances.idx(cls_def_id); - - let alloc_size = match cls.size { - InstanceSize::Fixed(size) => size as usize, - _ => unreachable!( - "class size type {:?} for new object not supported", - cls.size - ), - }; + let vtable = self.vm.vtable_for_class_instance_id(cls_def_id); + let alloc_size = vtable.instance_size(); let gcpoint = self.create_gcpoint(); let position = self.bytecode.offset_location(self.current_offset.to_u32()); @@ -2036,7 +1992,7 @@ impl<'a> CannonCodeGen<'a> { self.emit_store_register_as(REG_TMP1.into(), dest, MachineMode::Ptr); comment!(self, format!("NewEnum: initialize object")); - self.asm.initialize_object(REG_TMP1, &*cls); + self.asm.initialize_object(REG_TMP1, vtable); // store variant_idx comment!(self, format!("NewEnum: store variant_idx {}", variant_idx)); @@ -2050,11 +2006,11 @@ impl<'a> CannonCodeGen<'a> { let mut field_idx = 1; // first field is variant_idx - assert_eq!(arguments.len(), cls.fields.len() - 1); + assert_eq!(arguments.len(), vtable.fields.len() - 1); for arg in arguments { let ty = self.specialize_register_type(arg); - let field = &cls.fields[field_idx]; + let field = &vtable.fields[field_idx]; comment!(self, format!("NewEnum: store register {} in object", arg)); let dest = RegOrOffset::RegWithOffset(REG_TMP1, field.offset); @@ -2115,16 +2071,8 @@ impl<'a> CannonCodeGen<'a> { let class_instance_id = ensure_class_instance_for_trait_object(self.vm, trait_ty, object_ty.clone()); - - let cls = self.vm.class_instances.idx(class_instance_id); - - let alloc_size = match cls.size { - InstanceSize::Fixed(size) => size as usize, - _ => unreachable!( - "class size type {:?} for new object not supported", - cls.size - ), - }; + let vtable = self.vm.vtable_for_class_instance_id(class_instance_id); + let alloc_size = vtable.instance_size(); let gcpoint = self.create_gcpoint(); let position = self.bytecode.offset_location(self.current_offset.to_u32()); @@ -2143,10 +2091,10 @@ impl<'a> CannonCodeGen<'a> { self.emit_store_register_as(REG_TMP1.into(), dest, MachineMode::Ptr); comment!(self, format!("NewTraitObject: initialize object")); - self.asm.initialize_object(REG_TMP1, &*cls); + self.asm.initialize_object(REG_TMP1, vtable); - assert_eq!(cls.fields.len(), 1); - let field = &cls.fields[0]; + assert_eq!(vtable.fields.len(), 1); + let field = &vtable.fields[0]; comment!( self, format!("NewTraitObject: store register {} in object", src) @@ -2170,18 +2118,11 @@ impl<'a> CannonCodeGen<'a> { debug_assert!(type_params.iter().all(|ty| ty.is_concrete_type())); let cls_def_id = ensure_class_instance_for_lambda(self.vm, fct_id, type_params); + let vtable = self.vm.vtable_for_class_instance_id(cls_def_id); let arguments = self.argument_stack.drain(..).collect::>(); - let cls = self.vm.class_instances.idx(cls_def_id); - - let alloc_size = match cls.size { - InstanceSize::Fixed(size) => size as usize, - _ => unreachable!( - "class size type {:?} for new object not supported", - cls.size - ), - }; + let alloc_size = vtable.instance_size(); let gcpoint = self.create_gcpoint(); let position = self.bytecode.offset_location(self.current_offset.to_u32()); @@ -2202,7 +2143,7 @@ impl<'a> CannonCodeGen<'a> { self.emit_store_register_as(REG_TMP1.into(), dest, MachineMode::Ptr); comment!(self, format!("NewLambda: initialize object")); - self.asm.initialize_object(object_reg, &*cls); + self.asm.initialize_object(object_reg, vtable); // Store context pointer. if arguments.is_empty() { diff --git a/dora-runtime/src/size.rs b/dora-runtime/src/size.rs index ed3fdf590..bfe8e1347 100644 --- a/dora-runtime/src/size.rs +++ b/dora-runtime/src/size.rs @@ -38,7 +38,7 @@ impl InstanceSize { InstanceSize::Fixed(_) | InstanceSize::FillerWord => None, InstanceSize::FillerArray | InstanceSize::FreeSpace => Some(mem::ptr_width()), InstanceSize::StructArray(esize) => Some(*esize), - InstanceSize::UnitArray => None, + InstanceSize::UnitArray => Some(0), InstanceSize::CodeObject => Some(mem::ptr_width()), } } diff --git a/dora-runtime/src/vm.rs b/dora-runtime/src/vm.rs index 936f3f124..687eb47be 100644 --- a/dora-runtime/src/vm.rs +++ b/dora-runtime/src/vm.rs @@ -20,6 +20,8 @@ use crate::threads::{ STACK_SIZE, }; use crate::utils::GrowableVecNonIter; +use crate::VTable; + use dora_bytecode::{ BytecodeType, BytecodeTypeArray, ClassId, EnumId, FunctionId, ModuleId, Program, StructId, TraitId, @@ -135,7 +137,7 @@ pub struct VM { pub known: KnownElements, pub struct_specializations: RwLock>, pub struct_instances: GrowableVecNonIter, // stores all struct definitions - pub class_specializations: RwLock>, + pub class_specializations: RwLock>, pub class_instances: GrowableVecNonIter, // stores all class definitions pub code_objects: CodeObjects, pub compilation_database: CompilationDatabase, @@ -287,6 +289,16 @@ impl VM { self.gc.meta_space_size() } + pub fn vtable_for_class(&self, class_id: ClassId, type_params: &BytecodeTypeArray) -> &VTable { + let vtable = create_class_instance(self, class_id, type_params); + unsafe { &*vtable } + } + + pub fn vtable_for_class_instance_id(&self, id: ClassInstanceId) -> &VTable { + let vtable = self.class_instances.idx(id).vtable_ptr(); + unsafe { &*vtable } + } + pub fn class(&self, id: ClassId) -> &ClassData { &self.program.classes[id.0 as usize] } diff --git a/dora-runtime/src/vm/classes.rs b/dora-runtime/src/vm/classes.rs index 5c5c68a88..cde83ba82 100644 --- a/dora-runtime/src/vm/classes.rs +++ b/dora-runtime/src/vm/classes.rs @@ -67,13 +67,15 @@ impl ClassInstance { } pub fn vtable(&self) -> &VTable { - let vtable = self.vtable.get().cloned().expect("missing VTable"); - unsafe { &*vtable } + unsafe { &*self.vtable_ptr() } } - pub fn vtblptr(&self) -> Address { - let vtable = self.vtable.get().cloned().expect("missing VTable"); - Address::from_ptr(vtable) + pub fn vtable_ptr(&self) -> *const VTable { + self.vtable.get().cloned().expect("missing VTable") + } + + pub fn vtable_address(&self) -> Address { + Address::from_ptr(self.vtable_ptr()) } } diff --git a/dora-runtime/src/vm/initialize.rs b/dora-runtime/src/vm/initialize.rs index 8ecf3ef9f..ebea9fd7f 100644 --- a/dora-runtime/src/vm/initialize.rs +++ b/dora-runtime/src/vm/initialize.rs @@ -14,55 +14,55 @@ pub(super) fn setup(vm: &mut VM) { } fn create_special_classes(vm: &mut VM) { - let (_, filler_word_class_address) = create_class_instance_with_vtable( + let (_, filler_word_vtable) = create_class_instance_with_vtable( vm, ShapeKind::Builtin, InstanceSize::FillerWord, Vec::new(), 0, ); - vm.known.filler_word_vtable = Address::from_ptr(filler_word_class_address); + vm.known.filler_word_vtable = filler_word_vtable; - let (_, filler_array_class_address) = create_class_instance_with_vtable( + let (_, filler_array_vtable) = create_class_instance_with_vtable( vm, ShapeKind::Builtin, InstanceSize::FillerArray, Vec::new(), 0, ); - vm.known.filler_array_vtable = Address::from_ptr(filler_array_class_address); + vm.known.filler_array_vtable = filler_array_vtable; - let (_, free_space_class_address) = create_class_instance_with_vtable( + let (_, free_space_vtable) = create_class_instance_with_vtable( vm, ShapeKind::Builtin, InstanceSize::FreeSpace, Vec::new(), 0, ); - vm.known.free_space_vtable = Address::from_ptr(free_space_class_address); + vm.known.free_space_vtable = free_space_vtable; - let (_, code_class_address) = create_class_instance_with_vtable( + let (_, code_vtable) = create_class_instance_with_vtable( vm, ShapeKind::Builtin, InstanceSize::CodeObject, Vec::new(), 0, ); - vm.known.code_vtable = Address::from_ptr(code_class_address); + vm.known.code_vtable = code_vtable; let type_args = BytecodeTypeArray::one(BytecodeType::UInt8); - let cls_id = create_class_instance(vm, vm.known.array_class_id(), &type_args); - vm.known.byte_array_vtable = address_from_class_instance_id(vm, cls_id); + let vtable = create_class_instance(vm, vm.known.array_class_id(), &type_args); + vm.known.byte_array_vtable = vtable; let type_args = BytecodeTypeArray::one(BytecodeType::Int32); - let cls_id = create_class_instance(vm, vm.known.array_class_id(), &type_args); - vm.known.int32_array_vtable = address_from_class_instance_id(vm, cls_id); + let vtable = create_class_instance(vm, vm.known.array_class_id(), &type_args); + vm.known.int32_array_vtable = vtable; - let cls_id = create_class_instance(vm, vm.known.string_class_id(), &BytecodeTypeArray::empty()); - vm.known.string_vtable = address_from_class_instance_id(vm, cls_id); + let vtable = create_class_instance(vm, vm.known.string_class_id(), &BytecodeTypeArray::empty()); + vm.known.string_vtable = vtable; - let cls_id = create_class_instance(vm, vm.known.thread_class_id(), &BytecodeTypeArray::empty()); - vm.known.thread_vtable = address_from_class_instance_id(vm, cls_id); + let vtable = create_class_instance(vm, vm.known.thread_class_id(), &BytecodeTypeArray::empty()); + vm.known.thread_vtable = vtable; } fn address_from_class_instance_id(vm: &VM, id: ClassInstanceId) -> Address { diff --git a/dora-runtime/src/vm/known.rs b/dora-runtime/src/vm/known.rs index 7bf912164..c91c45811 100644 --- a/dora-runtime/src/vm/known.rs +++ b/dora-runtime/src/vm/known.rs @@ -1,20 +1,20 @@ -use std::cell::OnceCell; use std::collections::HashMap; +use std::{cell::OnceCell, ptr}; use crate::{gc::Address, vtable::VTable}; use dora_bytecode::{ClassId, FunctionId, TraitId}; #[derive(Debug)] pub struct KnownElements { - pub byte_array_vtable: Address, - pub int32_array_vtable: Address, - pub string_vtable: Address, - pub thread_vtable: Address, + pub byte_array_vtable: *const VTable, + pub int32_array_vtable: *const VTable, + pub string_vtable: *const VTable, + pub thread_vtable: *const VTable, - pub filler_word_vtable: Address, - pub filler_array_vtable: Address, - pub free_space_vtable: Address, - pub code_vtable: Address, + pub filler_word_vtable: *const VTable, + pub filler_array_vtable: *const VTable, + pub free_space_vtable: *const VTable, + pub code_vtable: *const VTable, pub zero_trait_id: Option, pub array_class_id: Option, @@ -30,15 +30,15 @@ pub struct KnownElements { impl KnownElements { pub fn new() -> KnownElements { KnownElements { - byte_array_vtable: Address::null(), - int32_array_vtable: Address::null(), - string_vtable: Address::null(), - thread_vtable: Address::null(), + byte_array_vtable: ptr::null(), + int32_array_vtable: ptr::null(), + string_vtable: ptr::null(), + thread_vtable: ptr::null(), - free_space_vtable: Address::null(), - filler_word_vtable: Address::null(), - filler_array_vtable: Address::null(), - code_vtable: Address::null(), + free_space_vtable: ptr::null(), + filler_word_vtable: ptr::null(), + filler_array_vtable: ptr::null(), + code_vtable: ptr::null(), zero_trait_id: None, array_class_id: None, @@ -53,35 +53,35 @@ impl KnownElements { } pub fn byte_array_vtable(&self) -> &VTable { - unsafe { &*self.byte_array_vtable.to_ptr::() } + unsafe { &*self.byte_array_vtable } } pub fn int32_array_vtable(&self) -> &VTable { - unsafe { &*self.int32_array_vtable.to_ptr::() } + unsafe { &*self.int32_array_vtable } } pub fn string_vtable(&self) -> &VTable { - unsafe { &*self.string_vtable.to_ptr::() } + unsafe { &*self.string_vtable } } pub fn thread_vtable(&self) -> &VTable { - unsafe { &*self.thread_vtable.to_ptr::() } + unsafe { &*self.thread_vtable } } pub fn filler_word_vtable(&self) -> &VTable { - unsafe { &*self.filler_word_vtable.to_ptr::() } + unsafe { &*self.filler_word_vtable } } pub fn filler_array_vtable(&self) -> &VTable { - unsafe { &*self.filler_array_vtable.to_ptr::() } + unsafe { &*self.filler_array_vtable } } pub fn free_space_vtable(&self) -> &VTable { - unsafe { &*self.free_space_vtable.to_ptr::() } + unsafe { &*self.free_space_vtable } } pub fn code_vtable(&self) -> &VTable { - unsafe { &*self.code_vtable.to_ptr::() } + unsafe { &*self.code_vtable } } pub fn zero_trait_id(&self) -> TraitId { diff --git a/dora-runtime/src/vm/specialize.rs b/dora-runtime/src/vm/specialize.rs index 474da3afd..acb459931 100644 --- a/dora-runtime/src/vm/specialize.rs +++ b/dora-runtime/src/vm/specialize.rs @@ -10,6 +10,7 @@ use crate::vm::{ EnumInstance, EnumInstanceId, EnumLayout, FieldInstance, ShapeKind, StructInstance, StructInstanceField, StructInstanceId, VM, }; +use crate::VTable; use dora_bytecode::{ BytecodeType, BytecodeTypeArray, ClassData, ClassId, EnumData, EnumId, FunctionId, Program, StructData, StructId, TraitId, @@ -286,34 +287,17 @@ pub fn create_class_instance( vm: &VM, cls_id: ClassId, type_params: &BytecodeTypeArray, -) -> ClassInstanceId { +) -> *const VTable { let cls = vm.class(cls_id); - specialize_class(vm, cls_id, cls, type_params) -} -fn specialize_class( - vm: &VM, - cls_id: ClassId, - cls: &ClassData, - type_params: &BytecodeTypeArray, -) -> ClassInstanceId { - if let Some(&id) = vm + if let Some(&vtable) = vm .class_specializations .read() .get(&(cls_id, type_params.clone())) { - return id; + return vtable; } - create_specialized_class(vm, cls_id, cls, type_params) -} - -fn create_specialized_class( - vm: &VM, - cls_id: ClassId, - cls: &ClassData, - type_params: &BytecodeTypeArray, -) -> ClassInstanceId { debug_assert!(type_params.iter().all(|ty| ty.is_concrete_type())); if vm.known.array_class_id() == cls_id || vm.known.string_class_id() == cls_id { @@ -328,7 +312,7 @@ fn create_specialized_class_regular( cls_id: ClassId, cls: &ClassData, type_params: &BytecodeTypeArray, -) -> ClassInstanceId { +) -> *const VTable { let mut csize = Header::size(); let mut fields = Vec::new(); let mut ref_fields = Vec::new(); @@ -355,11 +339,11 @@ fn create_specialized_class_regular( let mut specializations = vm.class_specializations.write(); - if let Some(&id) = specializations.get(&(cls_id, type_params.clone())) { - return id; + if let Some(&vtable) = specializations.get(&(cls_id, type_params.clone())) { + return vtable; } - let (class_instance_id, _) = create_class_instance_with_vtable( + let (_class_instance_id, vtable) = create_class_instance_with_vtable( vm, ShapeKind::Class(cls_id, type_params.clone()), size, @@ -367,10 +351,10 @@ fn create_specialized_class_regular( 0, ); - let old = specializations.insert((cls_id, type_params.clone()), class_instance_id); + let old = specializations.insert((cls_id, type_params.clone()), vtable); assert!(old.is_none()); - class_instance_id + vtable } fn create_specialized_class_array( @@ -378,7 +362,7 @@ fn create_specialized_class_array( cls_id: ClassId, cls: &ClassData, type_params: &BytecodeTypeArray, -) -> ClassInstanceId { +) -> *const VTable { assert!(cls.fields.is_empty()); let size = if vm.known.array_class_id() == cls_id { @@ -436,11 +420,11 @@ fn create_specialized_class_array( let mut specializations = vm.class_specializations.write(); - if let Some(&id) = specializations.get(&(cls_id, type_params.clone())) { - return id; + if let Some(&vtable) = specializations.get(&(cls_id, type_params.clone())) { + return vtable; } - let (class_instance_id, _) = create_class_instance_with_vtable( + let (_class_instance_id, vtable) = create_class_instance_with_vtable( vm, ShapeKind::Class(cls_id, type_params.clone()), size, @@ -448,10 +432,10 @@ fn create_specialized_class_array( 0, ); - let old = specializations.insert((cls_id, type_params.clone()), class_instance_id); + let old = specializations.insert((cls_id, type_params.clone()), vtable); assert!(old.is_none()); - class_instance_id + vtable } pub fn ensure_class_instance_for_lambda(