mmtk_macros/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use proc_macro::TokenStream;
use proc_macro_error::proc_macro_error;
use syn::parse_macro_input;
use syn::DeriveInput;

mod has_spaces_impl;
mod plan_trace_object_impl;
mod util;

const DEBUG_MACRO_OUTPUT: bool = false;

/// This macro will generate an implementation of `HasSpaces` for a plan or any structs that
/// contain spaces, including `Gen`, `CommonPlan` and `BasePlan`.
///
/// The `HasSpaces` trait is responsible for enumerating spaces in a struct.  When using this
/// derive macro, the user should do the following.
///
/// * Make sure the struct has a generic type parameter named `VM` which requires `VMBinding`.
///   For example, `struct MyPlan<VM: VMBinding>` will work.
/// * Add `#[space]` for each space field in the struct.
/// * Add `#[parent]` to the field that contain more space fields.  This attribute is usually
///   added to `Gen`, `CommonPlan` or `BasePlan` fields.  There can be at most one parent in
///   a struct.
#[proc_macro_error]
#[proc_macro_derive(HasSpaces, attributes(space, parent))]
pub fn derive_has_spaces(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let output = has_spaces_impl::derive(input);

    output.into()
}

/// The macro will generate an implementation of `PlanTraceObject` for the plan. With
/// `PlanTraceObject`, the plan will be able to use `PlanProcessEdges` for GC tracing.
///
/// The user should add `#[space]` and `#[parent]` attributes to fields as specified by the
/// `HasSpaces` trait.  When using this derive macro, all spaces must implement the
/// `PolicyTraceObject` trait.  The generated `trace_object` method will check for spaces in the
/// current plan and, if the object is not in any of them, check for plans in the parent struct.
/// The parent struct must also implement the `PlanTraceObject` trait.
///
/// In addition, the user can add the following attributes to fields in order to control the
/// behavior of the generated `trace_object` method.
///
/// * Add `#[copy_semantics(CopySemantics::X)]` to a space field to specify that when tracing
///   objects in that space, `Some(CopySemantics::X)` will be passed to the `Space::trace_object`
///   method as the `copy` argument.
/// * Add `#[post_scan]` to any space field that has some policy-specific `post_scan_object()`. For
///   objects in those spaces, `post_scan_object()` in the policy will be called after
///   `VM::VMScanning::scan_object()`.
#[proc_macro_error]
#[proc_macro_derive(PlanTraceObject, attributes(space, parent, copy_semantics, post_scan))]
pub fn derive_plan_trace_object(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let output = plan_trace_object_impl::derive(input);

    // Debug the output - use the following code to debug the generated code (when cargo exapand is not working)
    if DEBUG_MACRO_OUTPUT {
        use quote::ToTokens;
        println!("{}", output.to_token_stream());
    }

    output.into()
}