Skip to content

Commit

Permalink
Implement weak ref processing. Update mmtk-core. (#109)
Browse files Browse the repository at this point in the history
This adds weak reference support, and updates MMTk core to mmtk/mmtk-core#564.

* implement new changes in mmtk/mmtk-core#564
* properly set `referent` in `add_xxxx_candidates()`.
* Implement `get_boolean_option()` (see changes in mmtk/jikesrvm#12).
* add test with weak reference enabled (by default, it is disabled).
  • Loading branch information
qinsoon authored Apr 28, 2022
1 parent 01e49f0 commit a54b22f
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 132 deletions.
39 changes: 39 additions & 0 deletions .github/scripts/ci-test-weak-ref.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
set -xe

. $(dirname "$0")/common.sh

# To JikesRVM folder
cd $JIKESRVM_PATH

# Test FastAdaptive builds
# Run all possible dacapo benchmarks

export MMTK_THREADS=16
RVM_OPTIONS=-X:gc:no_reference_types=false

# RFastAdaptiveSemiSpace
./bin/buildit localhost RFastAdaptiveSemiSpace -j $JAVA_HOME --answer-yes --use-third-party-heap=$BINDING_PATH/ --use-third-party-build-configs=$BINDING_PATH/jikesrvm/build/configs --use-external-source=$BINDING_PATH/jikesrvm/rvm/src --m32
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar antlr
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar bloat
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms150M -Xmx150M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar eclipse
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar fop
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms200M -Xmx200M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar hsqldb
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar jython
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar luindex
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar lusearch
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar pmd
./dist/RFastAdaptiveSemiSpace_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms100M -Xmx100M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar xalan

# RFastAdaptiveMarkSweep
./bin/buildit localhost RFastAdaptiveMarkSweep -j $JAVA_HOME --answer-yes --use-third-party-heap=$BINDING_PATH/ --use-third-party-build-configs=$BINDING_PATH/jikesrvm/build/configs --use-external-source=$BINDING_PATH/jikesrvm/rvm/src --m32
./dist/RFastAdaptiveMarkSweep_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar bloat
# Failing instruction offset: 0x000000c3 in method ___ with descriptor ___ Couldn't find a method for given instruction offset
#./dist/RFastAdaptiveMarkSweep_x86_64-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar antlr - fail non-deterministically, basebase build runs fine with assertions
#./dist/RFastAdaptiveMarkSweep_x86_64-linux/rvm $RVM_OPTIONS -Xms150M -Xmx150M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar eclipse
./dist/RFastAdaptiveMarkSweep_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar fop
./dist/RFastAdaptiveMarkSweep_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms200M -Xmx200M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar hsqldb
./dist/RFastAdaptiveMarkSweep_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar jython
./dist/RFastAdaptiveMarkSweep_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar luindex
./dist/RFastAdaptiveMarkSweep_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar lusearch
./dist/RFastAdaptiveMarkSweep_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar pmd
./dist/RFastAdaptiveMarkSweep_x86_64_m32-linux/rvm $RVM_OPTIONS -Xms75M -Xmx75M -jar $DACAPO_PATH/dacapo-2006-10-MR2.jar xalan
4 changes: 3 additions & 1 deletion .github/scripts/ci-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ cur=$(realpath $(dirname "$0"))
cd $cur
./ci-test-normal.sh
cd $cur
./ci-test-assertions.sh
./ci-test-assertions.sh
cd $cur
./ci-test-weak-ref.sh
17 changes: 16 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,23 @@ jobs:
- name: Install MSRV
run: cargo install cargo-msrv
- name: Verify MSRV
id: verify-msrv
run: cargo msrv --path mmtk verify -- cargo check --features semispace --target i686-unknown-linux-gnu
# If the previous step fails, find MSRV
- name: Find MSRV
if: failure()
if: ${{ steps.verify-msrv.outcome == 'failure' }}
run: cargo msrv --path mmtk -- cargo check --features semispace --target i686-unknown-linux-gnu

test-weak-ref:
runs-on: ubuntu-18.04
steps:
# Checkout repos
- uses: actions/checkout@v2
- name: Setup Environments
run: |
./.github/scripts/ci-checkout.sh
./.github/scripts/ci-setup.sh
# Run the tests
- name: Dacapo Tests
run: ./.github/scripts/ci-test-weak-ref.sh
4 changes: 2 additions & 2 deletions mmtk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ lto = true
[package.metadata.jikesrvm]
# Our CI matches the following line and extract mmtk/jikesrvm. If this line is updated, please check ci yaml files and make sure it works.
jikesrvm_repo = "https://github.com/mmtk/jikesrvm.git"
jikesrvm_version = "b13031ee4d6ebcaf8330d7e4a8992b13c6332d61"
jikesrvm_version = "c3258092e8eb99d09e0e6b975d7528bcd7fb2429"

[dependencies]
libc = "0.2"
Expand All @@ -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 = "0babba20290d3c4e4cdb2a83284aa7204c9a23cc" }
mmtk = { git = "https://github.com/mmtk/mmtk-core.git", rev = "21176127d1f0493444fd901ea7277099a24bcecc" }
# 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
2 changes: 2 additions & 0 deletions mmtk/api/mmtk.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ extern void add_weak_candidate(void* ref, void* referent);
extern void add_soft_candidate(void* ref, void* referent);
extern void add_phantom_candidate(void* ref, void* referent);

extern bool get_boolean_option(char* option);

/**
* Finalization
*/
Expand Down
23 changes: 20 additions & 3 deletions mmtk/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use mmtk::memory_manager;
use mmtk::scheduler::*;
use mmtk::util::opaque_pointer::*;
use mmtk::util::{Address, ObjectReference};
use mmtk::vm::{ReferenceGlue, VMBinding};
use mmtk::AllocationSemantics;
use mmtk::Mutator;
use mmtk::MMTK;
Expand Down Expand Up @@ -159,17 +160,33 @@ pub extern "C" fn modify_check(object: ObjectReference) {

#[no_mangle]
pub extern "C" fn add_weak_candidate(reff: ObjectReference, referent: ObjectReference) {
memory_manager::add_weak_candidate(&SINGLETON, reff, referent)
<JikesRVM as VMBinding>::VMReferenceGlue::set_referent(reff, referent);
memory_manager::add_weak_candidate(&SINGLETON, reff)
}

#[no_mangle]
pub extern "C" fn add_soft_candidate(reff: ObjectReference, referent: ObjectReference) {
memory_manager::add_soft_candidate(&SINGLETON, reff, referent)
<JikesRVM as VMBinding>::VMReferenceGlue::set_referent(reff, referent);
memory_manager::add_soft_candidate(&SINGLETON, reff)
}

#[no_mangle]
pub extern "C" fn add_phantom_candidate(reff: ObjectReference, referent: ObjectReference) {
memory_manager::add_phantom_candidate(&SINGLETON, reff, referent)
<JikesRVM as VMBinding>::VMReferenceGlue::set_referent(reff, referent);
memory_manager::add_phantom_candidate(&SINGLETON, reff)
}

#[no_mangle]
// We trust the name/value pointer is valid.
#[allow(clippy::not_unsafe_ptr_arg_deref)]
// For a syscall that returns bool, we have to return a i32 instead. See https://github.com/mmtk/mmtk-jikesrvm/issues/20
pub extern "C" fn get_boolean_option(option: *const c_char) -> i32 {
let option_str: &CStr = unsafe { CStr::from_ptr(option) };
if option_str.to_str().unwrap() == "noReferenceTypes" {
*SINGLETON.get_options().no_reference_types as i32
} else {
unimplemented!()
}
}

#[no_mangle]
Expand Down
134 changes: 9 additions & 125 deletions mmtk/src/reference_glue.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
use libc::c_void;

use mmtk::util::opaque_pointer::*;
use mmtk::util::reference_processor::*;
use mmtk::util::{Address, ObjectReference};
use mmtk::util::ObjectReference;
use mmtk::vm::ReferenceGlue;
use mmtk::TraceLocal;

use entrypoint::*;
use JikesRVM;
Expand All @@ -16,7 +12,7 @@ pub struct VMReferenceGlue {}
impl ReferenceGlue<JikesRVM> for VMReferenceGlue {
fn set_referent(reff: ObjectReference, referent: ObjectReference) {
unsafe {
(reff.to_address() + REFERENCE_REFERENT_FIELD_OFFSET).store(referent.value());
(reff.to_address() + REFERENCE_REFERENT_FIELD_OFFSET).store(referent);
}
}

Expand All @@ -25,127 +21,15 @@ impl ReferenceGlue<JikesRVM> for VMReferenceGlue {
unsafe { (object.to_address() + REFERENCE_REFERENT_FIELD_OFFSET).load::<ObjectReference>() }
}

/**
* Processes a reference with the current semantics.
* <p>
* This method deals with a soft reference as if it were a weak reference, i.e.
* it does not retain the referent. To retain the referent, use
* {@link #retainReferent(TraceLocal, ObjectReference)} followed by a transitive
* closure phase.
*
* @param reference the address of the reference. This may or may not
* be the address of a heap object, depending on the VM.
* @param trace the thread local trace element.
* @return an updated reference (e.g. with a new address) if the reference
* is still live, {@code ObjectReference.nullReference()} otherwise
*/
fn process_reference<T: TraceLocal>(
trace: &mut T,
reference: ObjectReference,
tls: VMWorkerThread,
) -> ObjectReference {
debug_assert!(!reference.is_null());

if TRACE_DETAIL {
trace!("Processing reference: {:?}", reference);
}

/*
* If the reference is dead, we're done with it. Let it (and
* possibly its referent) be garbage-collected.
*/
if !reference.is_live() {
VMReferenceGlue::clear_referent(reference); // Too much paranoia ...
if TRACE_UNREACHABLE {
trace!(" UNREACHABLE reference: {:?}", reference);
}
if TRACE_DETAIL {
trace!(" (unreachable)");
}
return unsafe { Address::zero().to_object_reference() };
}

/* The reference object is live */
let new_reference = trace.get_forwarded_reference(reference);
let old_referent = VMReferenceGlue::get_referent(reference);

if TRACE_DETAIL {
trace!(" ~> {:?}", old_referent);
}

/*
* If the application has cleared the referent the Java spec says
* this does not cause the Reference object to be enqueued. We
* simply allow the Reference object to fall out of our
* waiting list.
*/
if old_referent.is_null() {
if TRACE_DETAIL {
trace!("(null referent)");
}
return unsafe { Address::zero().to_object_reference() };
}

if TRACE_DETAIL {
trace!(" => {:?}", new_reference);
}

if old_referent.is_live() {
if cfg!(feature = "debug") {
// FIXME
/*if (!DebugUtil.validRef(oldReferent)) {
VM.sysWriteln("Error in old referent.");
DebugUtil.dumpRef(oldReferent);
VM.sysFail("Invalid reference");
}*/
}

/*
* Referent is still reachable in a way that is as strong as
* or stronger than the current reference level.
*/
let new_referent = trace.get_forwarded_referent(old_referent);

if TRACE_DETAIL {
trace!(" ~> {:?}", new_referent);
}

if cfg!(feature = "debug") {
// FIXME
/*if (!DebugUtil.validRef(newReferent)) {
VM.sysWriteln("Error forwarding reference object.");
DebugUtil.dumpRef(oldReferent);
VM.sysFail("Invalid reference");
}*/
debug_assert!(new_reference.is_live());
}

/*
* The reference object stays on the waiting list, and the
* referent is untouched. The only thing we must do is
* ensure that the former addresses are updated with the
* new forwarding addresses in case the collector is a
* copying collector.
*/

/* Update the referent */
VMReferenceGlue::set_referent(new_reference, new_referent);
new_reference
} else {
/* Referent is unreachable. Clear the referent and enqueue the reference object. */

if TRACE_DETAIL {
trace!(" UNREACHABLE");
} else if TRACE_UNREACHABLE {
trace!(" UNREACHABLE referent: {:?}", old_referent);
}

VMReferenceGlue::clear_referent(new_reference);
let new_reference_raw = new_reference.value() as *mut c_void;
fn enqueue_references(references: &[ObjectReference], tls: VMWorkerThread) {
for reff in references {
unsafe {
jtoc_call!(ENQUEUE_REFERENCE_METHOD_OFFSET, tls, new_reference_raw);
jtoc_call!(
ENQUEUE_REFERENCE_METHOD_OFFSET,
tls,
std::mem::transmute::<_, usize>(*reff)
);
}
unsafe { Address::zero().to_object_reference() }
}
}
}

0 comments on commit a54b22f

Please sign in to comment.