Skip to content
Closed
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
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ perf_counter = ["pfm"]
# spaces
vm_space = []
ro_space = []
code_space = []
code_space = []
malloc_space = []

# metadata
global_alloc_bit = []
Expand Down
10 changes: 10 additions & 0 deletions src/memory_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ pub fn post_alloc<VM: VMBinding>(
mutator.post_alloc(refer, bytes, semantics);
}

#[cfg(feature = "malloc_space")]
pub fn free<VM: VMBinding>(mmtk: &MMTK<VM>, address: Address) {
mmtk.plan.base().malloc_space.free_manually(address)
}

#[cfg(feature = "malloc_space")]
pub fn malloc_usable_size<VM: VMBinding>(mmtk: &MMTK<VM>, address: Address) -> usize {
mmtk.plan.base().malloc_space.malloc_usable_size(address)
}

/// Return an AllocatorSelector for the given allocation semantic. This method is provided
/// so that VM compilers may call it to help generate allocation fast-path.
///
Expand Down
52 changes: 52 additions & 0 deletions src/plan/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::plan::transitive_closure::TransitiveClosure;
use crate::plan::Mutator;
use crate::policy::immortalspace::ImmortalSpace;
use crate::policy::largeobjectspace::LargeObjectSpace;
#[cfg(feature = "malloc_space")]
use crate::policy::mallocspace::MallocSpace;
use crate::policy::space::Space;
use crate::scheduler::*;
use crate::util::alloc::allocators::AllocatorSelector;
Expand Down Expand Up @@ -376,13 +378,23 @@ pub struct BasePlan<VM: VMBinding> {
pub analysis_manager: AnalysisManager<VM>,

// Spaces in base plan
/// Code space allows execution.
// TODO: a proper CodeSpace.
#[cfg(feature = "code_space")]
pub code_space: ImmortalSpace<VM>,
#[cfg(feature = "code_space")]
pub code_lo_space: ImmortalSpace<VM>,

/// Read-only space does not allow write once read-only is enabled.
// TODO: a proper ReadOnlySpace
#[cfg(feature = "ro_space")]
pub ro_space: ImmortalSpace<VM>,

/// Malloc space allows manual malloc/free-alike API.
/// A user allocate into a malloc space with [`AllocationSemantics::Malloc`](crate::plan::AllocationSemantics)
#[cfg(feature = "malloc_space")]
pub malloc_space: MallocSpace<VM>,

/// A VM space is a space allocated and populated by the VM. Currently it is used by JikesRVM
/// for boot image.
///
Expand Down Expand Up @@ -478,6 +490,8 @@ impl<VM: VMBinding> BasePlan<VM> {
&mut heap,
constraints,
),
#[cfg(feature = "malloc_space")]
malloc_space: MallocSpace::new(false, global_side_metadata_specs.clone()),
#[cfg(feature = "vm_space")]
vm_space: create_vm_space(
vm_map,
Expand Down Expand Up @@ -532,6 +546,8 @@ impl<VM: VMBinding> BasePlan<VM> {
self.code_lo_space.init(vm_map);
#[cfg(feature = "ro_space")]
self.ro_space.init(vm_map);
#[cfg(feature = "malloc_space")]
self.malloc_space.init(vm_map);
#[cfg(feature = "vm_space")]
{
self.vm_space.init(vm_map);
Expand Down Expand Up @@ -588,6 +604,10 @@ impl<VM: VMBinding> BasePlan<VM> {
{
pages += self.ro_space.reserved_pages();
}
#[cfg(feature = "malloc_space")]
{
pages += self.malloc_space.reserved_pages();
}

// The VM space may be used as an immutable boot image, in which case, we should not count
// it as part of the heap size.
Expand Down Expand Up @@ -617,6 +637,11 @@ impl<VM: VMBinding> BasePlan<VM> {
return self.ro_space.trace_object(_trace, _object);
}

#[cfg(feature = "malloc_space")]
if self.malloc_space.in_space(_object) {
panic!("We cannot trace object in malloc_space");
}

#[cfg(feature = "vm_space")]
if self.vm_space.in_space(_object) {
trace!("trace_object: object in boot space");
Expand All @@ -632,6 +657,10 @@ impl<VM: VMBinding> BasePlan<VM> {
self.code_lo_space.prepare();
#[cfg(feature = "ro_space")]
self.ro_space.prepare();
#[cfg(feature = "malloc_space")]
{
// We do not need to prepare for malloc space
}
#[cfg(feature = "vm_space")]
self.vm_space.prepare();
}
Expand All @@ -643,6 +672,10 @@ impl<VM: VMBinding> BasePlan<VM> {
self.code_lo_space.release();
#[cfg(feature = "ro_space")]
self.ro_space.release();
#[cfg(feature = "malloc_space")]
{
// We do not need to release for malloc space
}
#[cfg(feature = "vm_space")]
self.vm_space.release();
}
Expand Down Expand Up @@ -825,6 +858,9 @@ impl<VM: VMBinding> BasePlan<VM> {
#[cfg(feature = "ro_space")]
self.ro_space
.verify_side_metadata_sanity(side_metadata_sanity_checker);
#[cfg(feature = "malloc_space")]
self.malloc_space
.verify_side_metadata_sanity(side_metadata_sanity_checker);
#[cfg(feature = "vm_space")]
self.vm_space
.verify_side_metadata_sanity(side_metadata_sanity_checker);
Expand Down Expand Up @@ -951,10 +987,26 @@ use enum_map::Enum;
#[repr(i32)]
#[derive(Clone, Copy, Debug, Enum, PartialEq, Eq)]
pub enum AllocationSemantics {
/// The default allocation semantic. Most allocation should use this semantic.
Default = 0,
/// This semantic guarantees the memory won't be reclaimed by GC.
Immortal = 1,
/// Large object. Generally a plan defines a constant `max_non_los_default_alloc_bytes`,
/// which specifies the max object size that can be allocated with the Default allocation semantic.
/// An object that is larger than the defined max size needs to be allocated with `Los`.
Los = 2,
/// This semantic guarantees the memory will not be moved and has the execution permission.
Code = 3,
/// This semantic allows the memory to be made read-only after allocation.
/// This semantic is not implemented yet.
ReadOnly = 4,
/// Large object + Code.
LargeCode = 5,
/// Malloc and free through MMTk. Note that when this is used, the user should treat the result
/// as if it is returned from malloc():
/// * The memory needs to be manually freed by the user.
/// * The user should not use any other API other than `free()` and `malloc_usable_size()` for the
/// memory address we return. MMTk may panic if the user casts the memory address into an object
/// reference, and pass the object reference in MMTk's API.
Malloc = 6,
}
7 changes: 6 additions & 1 deletion src/plan/marksweep/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,13 @@ impl<VM: VMBinding> MarkSweep<VM> {
ACTIVE_CHUNK_METADATA_SPEC,
]);

if cfg!(feature = "malloc_space") {
// We can remove this check once we no longer use malloc marksweep.
panic!("We only allow one malloc space in use (marksweep currently uses malloc space and performs marksweep on it");
}

let res = MarkSweep {
ms: MallocSpace::new(global_metadata_specs.clone()),
ms: MallocSpace::new(true, global_metadata_specs.clone()),
common: CommonPlan::new(
vm_map,
mmapper,
Expand Down
15 changes: 15 additions & 0 deletions src/plan/mutator_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ pub(crate) fn create_allocator_mapping(
reserved.n_bump_pointer += 1;
}

#[cfg(feature = "malloc_space")]
{
map[AllocationSemantics::Malloc] = AllocatorSelector::Malloc(reserved.n_malloc);
reserved.n_malloc += 1;
}

// spaces in common plan

if include_common_plan {
Expand Down Expand Up @@ -282,6 +288,15 @@ pub(crate) fn create_space_mapping<VM: VMBinding>(
reserved.n_bump_pointer += 1;
}

#[cfg(feature = "malloc_space")]
{
vec.push((
AllocatorSelector::Malloc(reserved.n_malloc),
&plan.base().malloc_space,
));
reserved.n_malloc += 1;
}

// spaces in CommonPlan

if include_common_plan {
Expand Down
Loading