Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No ProcessEdgesWork in API functions #114

Merged
merged 4 commits into from
Jul 5, 2022
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
44 changes: 29 additions & 15 deletions jikesrvm/rvm/src/org/jikesrvm/mm/mminterface/RustScanThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@
private GCMapIterator iterator;
@Untraced
private boolean processCodeLocations;
private Address process_edges;
private Address report_edges;
private Address report_edges_extra_data;
@Untraced
private RVMThread thread;
private Address ip, fp, prevFp, initialIPLoc, topFrame;
Expand All @@ -121,7 +122,8 @@

private Address edges;
private Word size = Word.zero();
// The buffer size of mmtk-core's `ProcessEdgesWork` work packet.
// The buffer size agreed between the Rust part and the Java part of the binding.
// See the constant EDGES_BUFFER_CAPACITY in scanning.rs.
public static final Word EDGES_BUFFER_CAPACITY = Word.fromIntZeroExtend(4096);

/***********************************************************************
Expand All @@ -133,13 +135,17 @@
* Scan a thread, placing the addresses of pointers into supplied buffers.
*
* @param thread The thread to be scanned
* @param trace The trace instance to use for reporting references.
* @param report_edges The native call-back function to use for reporting locations.
* @param report_edges_extra_data Extra data passed to the report_edges call-back.
* @param processCodeLocations Should code locations be processed?
* @param newRootsSufficient Is a partial stack scan sufficient, or must we do a full scan?
*/
@Entrypoint
public static void scanThread(RVMThread thread, Address process_edges,
boolean processCodeLocations, boolean newRootsSufficient) {
public static void scanThread(RVMThread thread,
Address report_edges,
Address report_edges_extra_data,
boolean processCodeLocations,
boolean newRootsSufficient) {
if (DEFAULT_VERBOSITY >= 1) {
VM.sysWriteln("scanning ",thread.getThreadSlot());
}
Expand All @@ -152,7 +158,7 @@ public static void scanThread(RVMThread thread, Address process_edges,
Address fp = regs.getInnermostFramePointer();
regs.clear();
regs.setInnermost(ip,fp);
scanThread(thread, process_edges, processCodeLocations, gprs, Address.zero(), newRootsSufficient);
scanThread(thread, report_edges, report_edges_extra_data, processCodeLocations, gprs, Address.zero(), newRootsSufficient);
}

/**
Expand All @@ -161,17 +167,22 @@ public static void scanThread(RVMThread thread, Address process_edges,
* structure.
*
* @param thread The thread to be scanned
* @param trace The trace instance to use for reporting references.
* @param report_edges The native call-back function to use for reporting locations.
* @param report_edges_extra_data Extra data passed to the report_edges call-back.
* @param processCodeLocations Should code locations be processed?
* @param gprs The general purpose registers associated with the
* stack being scanned (normally extracted from the thread).
* @param topFrame The top frame of the stack being scanned, or zero
* if this is to be inferred from the thread (normally the case).
* @param newRootsSufficent Is a partial stack scan sufficient, or must we do a full scan?
*/
private static void scanThread(RVMThread thread, Address process_edges,
private static void scanThread(RVMThread thread,
Address report_edges,
Address report_edges_extra_data,
boolean processCodeLocations,
Address gprs, Address topFrame, boolean newRootsSufficent) {
Address gprs,
Address topFrame,
boolean newRootsSufficent) {
// figure out if the thread should be scanned at all; if not, exit
if (thread.getExecStatus() == RVMThread.NEW || thread.getIsAboutToTerminate()) {
return;
Expand Down Expand Up @@ -200,7 +211,7 @@ private static void scanThread(RVMThread thread, Address process_edges,
}

/* scan the stack */
scanner.startScan(process_edges, processCodeLocations, thread, gprs, ip, fp, initialIPLoc, topFrame, sentinelFp);
scanner.startScan(report_edges, report_edges_extra_data, processCodeLocations, thread, gprs, ip, fp, initialIPLoc, topFrame, sentinelFp);
}

@Inline
Expand All @@ -218,7 +229,7 @@ private void reportEdge(Address edge) {

private void flush() {
if (!edges.isZero() && !size.isZero()) {
edges = sysCall.sysDynamicCall2(process_edges, edges.toWord(), size);
edges = sysCall.sysDynamicCall3(report_edges, edges.toWord(), size, report_edges_extra_data.toWord());
size = Word.zero();
}
}
Expand All @@ -233,7 +244,8 @@ private void flush() {
* The various state associated with stack scanning is captured by
* instance variables of this type, which are initialized here.
*
* @param trace The trace instance to use for reporting locations.
* @param report_edges The native call-back function to use for reporting locations.
* @param report_edges_extra_data Extra data passed to the report_edges call-back.
* @param processCodeLocations whether to process parts of the thread
* that could point to code (e.g. exception registers).
* @param thread Thread for the thread whose stack is being scanned
Expand All @@ -249,14 +261,16 @@ private void flush() {
* if this is to be inferred from the thread (normally the case).
* @param sentinelFp The frame pointer at which the stack scan should stop.
*/
private void startScan(Address process_edges,
private void startScan(Address report_edges,
Address report_edges_extra_data,
boolean processCodeLocations,
RVMThread thread, Address gprs, Address ip,
Address fp, Address initialIPLoc, Address topFrame,
Address sentinelFp) {
this.process_edges = process_edges;
this.report_edges = report_edges;
this.report_edges_extra_data = report_edges_extra_data;
this.size = Word.zero();
this.edges = sysCall.sysDynamicCall2(process_edges, Word.zero(), Word.zero());
this.edges = sysCall.sysDynamicCall3(report_edges, Word.zero(), Word.zero(), report_edges_extra_data.toWord());

this.processCodeLocations = processCodeLocations;
this.thread = thread;
Expand Down
2 changes: 1 addition & 1 deletion jikesrvm/rvm/src/org/jikesrvm/runtime/Entrypoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class Entrypoints {
// These are the changes made from our JikesRVM fork
public static final NormalMethod scanThreadMethod =
getMethod(org.jikesrvm.mm.mminterface.RustScanThread.class, "scanThread",
"(Lorg/jikesrvm/scheduler/RVMThread;Lorg/vmmagic/unboxed/Address;ZZ)V");
"(Lorg/jikesrvm/scheduler/RVMThread;Lorg/vmmagic/unboxed/Address;Lorg/vmmagic/unboxed/Address;ZZ)V");
public static final NormalMethod scanBootImageMethod =
getMethod(org.jikesrvm.mm.mminterface.RustScanning.class, "scanBootImage", "(Lorg/vmmagic/unboxed/Address;)V");
public static final NormalMethod scheduleFinalizerMethod =
Expand Down
2 changes: 1 addition & 1 deletion mmtk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ log = {version = "0.4", features = ["max_level_trace", "release_max_level_off"]
# - change branch/rev
# - change repo name
# But other changes including adding/removing whitespaces in commented lines may break the CI.
mmtk = { git = "https://github.com/mmtk/mmtk-core.git", rev = "571a857b75e648ca4c711d56fbf400d99173398f" }
mmtk = { git = "https://github.com/mmtk/mmtk-core.git", rev = "f0fed5fc01438162115120c7551d4eb96e888bc2" }
# Uncomment the following to build locally - if you change the path locally, do not commit the change in a PR
# mmtk = { path = "../repos/mmtk-core" }

Expand Down
4 changes: 2 additions & 2 deletions mmtk/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::scanning::PROCESS_EDGES_WORK_SIZE;
use crate::scanning::EDGES_BUFFER_CAPACITY;
use collection::VMCollection;
use collection::BOOT_THREAD;
use libc::c_char;
Expand All @@ -20,7 +20,7 @@ use SINGLETON;
/// Caller needs to make sure the ptr is a valid vector pointer.
#[no_mangle]
pub unsafe extern "C" fn release_buffer(ptr: *mut Address) {
let _vec = Vec::<Address>::from_raw_parts(ptr, 0, PROCESS_EDGES_WORK_SIZE);
let _vec = Vec::<Address>::from_raw_parts(ptr, 0, EDGES_BUFFER_CAPACITY);
}

#[no_mangle]
Expand Down
7 changes: 5 additions & 2 deletions mmtk/src/collection.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use entrypoint::*;
use mmtk::scheduler::*;
use mmtk::util::alloc::AllocationError;
use mmtk::util::opaque_pointer::*;
use mmtk::util::Address;
use mmtk::vm::{Collection, GCThreadContext};
use mmtk::Mutator;
use mmtk::MutatorContext;
use JikesRVM;
use JTOC_BASE;
Expand All @@ -18,7 +18,10 @@ pub struct VMCollection {}
// FIXME: Shouldn't these all be unsafe because of tls?
impl Collection<JikesRVM> for VMCollection {
#[inline(always)]
fn stop_all_mutators<E: ProcessEdgesWork<VM = JikesRVM>>(tls: VMWorkerThread) {
fn stop_all_mutators<F>(tls: VMWorkerThread, _mutator_visitor: F)
where
F: FnMut(&'static mut Mutator<JikesRVM>),
{
unsafe {
jtoc_call!(BLOCK_ALL_MUTATORS_FOR_GC_METHOD_OFFSET, tls);
}
Expand Down
54 changes: 31 additions & 23 deletions mmtk/src/scan_boot_image.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use crate::scanning::EDGES_BUFFER_CAPACITY;
use crate::unboxed_size_constants::*;
use crate::{JikesRVM, SINGLETON};
use crate::JikesRVM;
use entrypoint::*;
use java_size_constants::*;
use mmtk::memory_manager;
use mmtk::scheduler::*;
use mmtk::util::conversions;
use mmtk::util::Address;
use mmtk::util::OpaquePointer;
use mmtk::vm::RootsWorkFactory;
use mmtk::MMTK;
use std::marker::PhantomData;
use std::mem;
use std::sync::atomic::{AtomicUsize, Ordering};
use JTOC_BASE;
Expand All @@ -23,8 +23,9 @@ const LONGENCODING_OFFSET_BYTES: usize = 4;
static ROOTS: AtomicUsize = AtomicUsize::new(0);
static REFS: AtomicUsize = AtomicUsize::new(0);

pub fn scan_boot_image<W: ProcessEdgesWork<VM = JikesRVM>>(
pub fn scan_boot_image(
_tls: OpaquePointer,
factory: &mut impl RootsWorkFactory,
subwork_id: usize,
total_subwork: usize,
) {
Expand All @@ -51,24 +52,18 @@ pub fn scan_boot_image<W: ProcessEdgesWork<VM = JikesRVM>>(
trace!("Processing chunk at {:x}", cursor);
process_chunk(cursor, image_start, map_start, map_end, |edge| {
edges.push(edge);
if edges.len() >= W::CAPACITY {
let mut new_edges = Vec::with_capacity(W::CAPACITY);
mem::swap(&mut new_edges, &mut edges);
memory_manager::add_work_packet(
&SINGLETON,
WorkBucketStage::Closure,
W::new(new_edges, true, &SINGLETON),
);
if edges.len() >= EDGES_BUFFER_CAPACITY {
let new_edges =
mem::replace(&mut edges, Vec::with_capacity(EDGES_BUFFER_CAPACITY));
factory.create_process_edge_roots_work(new_edges);
}
});
trace!("Chunk processed successfully");
cursor += stride;
}
memory_manager::add_work_packet(
&SINGLETON,
WorkBucketStage::Closure,
W::new(edges, true, &SINGLETON),
);
if !edges.is_empty() {
factory.create_process_edge_roots_work(edges);
}
}
}

Expand Down Expand Up @@ -145,16 +140,29 @@ fn decode_long_encoding(cursor: Address) -> usize {
}
}

pub struct ScanBootImageRoots<E: ProcessEdgesWork<VM = JikesRVM>>(usize, usize, PhantomData<E>);
pub struct ScanBootImageRoots<F: RootsWorkFactory> {
factory: F,
subwork_id: usize,
total_subwork: usize,
}

impl<E: ProcessEdgesWork<VM = JikesRVM>> ScanBootImageRoots<E> {
pub fn new(subwork_id: usize, total_subwork: usize) -> Self {
Self(subwork_id, total_subwork, PhantomData)
impl<F: RootsWorkFactory> ScanBootImageRoots<F> {
pub fn new(factory: F, subwork_id: usize, total_subwork: usize) -> Self {
Self {
factory,
subwork_id,
total_subwork,
}
}
}

impl<E: ProcessEdgesWork<VM = JikesRVM>> GCWork<JikesRVM> for ScanBootImageRoots<E> {
impl<F: RootsWorkFactory> GCWork<JikesRVM> for ScanBootImageRoots<F> {
fn do_work(&mut self, _worker: &mut GCWorker<JikesRVM>, _mmtk: &'static MMTK<JikesRVM>) {
scan_boot_image::<E>(OpaquePointer::UNINITIALIZED, self.0, self.1);
scan_boot_image(
OpaquePointer::UNINITIALIZED,
&mut self.factory,
self.subwork_id,
self.total_subwork,
);
}
}
54 changes: 31 additions & 23 deletions mmtk/src/scan_statics.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::{JikesRVM, SINGLETON};
use crate::scanning::EDGES_BUFFER_CAPACITY;
use crate::JikesRVM;
use entrypoint::*;
use mmtk::memory_manager;
use mmtk::scheduler::*;
use mmtk::util::opaque_pointer::*;
use mmtk::vm::RootsWorkFactory;
use mmtk::MMTK;
use std::arch::asm;
use std::marker::PhantomData;
use JTOC_BASE;

#[cfg(target_pointer_width = "32")]
Expand All @@ -15,8 +15,9 @@ const REF_SLOT_SIZE: usize = 2;

const CHUNK_SIZE_MASK: usize = 0xFFFFFFFF - (REF_SLOT_SIZE - 1);

pub fn scan_statics<W: ProcessEdgesWork<VM = JikesRVM>>(
pub fn scan_statics(
tls: VMWorkerThread,
factory: &mut impl RootsWorkFactory,
subwork_id: usize,
total_subwork: usize,
) {
Expand All @@ -41,42 +42,49 @@ pub fn scan_statics<W: ProcessEdgesWork<VM = JikesRVM>>(
(thread_ordinal + 1) * chunk_size
};

let mut edges = Vec::with_capacity(W::CAPACITY);
let mut edges = Vec::with_capacity(EDGES_BUFFER_CAPACITY);

let mut slot = start;
while slot < end {
let slot_offset = slot * 4;
// TODO: check_reference?
edges.push(slots + slot_offset);
if edges.len() >= W::CAPACITY {
memory_manager::add_work_packet(
&SINGLETON,
WorkBucketStage::Closure,
W::new(edges, true, &SINGLETON),
);
edges = Vec::with_capacity(W::CAPACITY);
if edges.len() >= EDGES_BUFFER_CAPACITY {
factory.create_process_edge_roots_work(edges);
edges = Vec::with_capacity(EDGES_BUFFER_CAPACITY);
}
// trace.process_root_edge(slots + slot_offset, true);
slot += REF_SLOT_SIZE;
}
memory_manager::add_work_packet(
&SINGLETON,
WorkBucketStage::Closure,
W::new(edges, true, &SINGLETON),
);
if !edges.is_empty() {
factory.create_process_edge_roots_work(edges);
}
}
}

pub struct ScanStaticRoots<E: ProcessEdgesWork<VM = JikesRVM>>(usize, usize, PhantomData<E>);
pub struct ScanStaticRoots<F: RootsWorkFactory> {
factory: F,
subwork_id: usize,
total_subwork: usize,
}

impl<E: ProcessEdgesWork<VM = JikesRVM>> ScanStaticRoots<E> {
pub fn new(subwork_id: usize, total_subwork: usize) -> Self {
Self(subwork_id, total_subwork, PhantomData)
impl<F: RootsWorkFactory> ScanStaticRoots<F> {
pub fn new(factory: F, subwork_id: usize, total_subwork: usize) -> Self {
Self {
factory,
subwork_id,
total_subwork,
}
}
}

impl<E: ProcessEdgesWork<VM = JikesRVM>> GCWork<JikesRVM> for ScanStaticRoots<E> {
impl<F: RootsWorkFactory> GCWork<JikesRVM> for ScanStaticRoots<F> {
fn do_work(&mut self, worker: &mut GCWorker<JikesRVM>, _mmtk: &'static MMTK<JikesRVM>) {
scan_statics::<E>(worker.tls, self.0, self.1);
scan_statics(
worker.tls,
&mut self.factory,
self.subwork_id,
self.total_subwork,
);
}
}
Loading