-
Notifications
You must be signed in to change notification settings - Fork 1.4k
(READY FOR REVIEW)Garbage collect: A stop-the-world cycle collector #4180
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
feat: add double drop check in debug mode fix: use Mutex instead of PyMutex in `ID2TYPE` refactor: cfg cond for `Drop` trait instead feat: add `Trace` trait feat: trace RwLock right&trace tuple feat: `Trace` for `PyDict` feat: `Trace` on `PyIter`&`PyIterReturn`&`PyIterIter` feat: `Trace` on PyEnumerate feat: `Trace` on `ArgCallable` `ArgIterable` `ArgMapping` `ArgSequence` feat: `Trace` on `IterStatus` `PySequenceIterator` `PyCallableIterator` `PositionIterInternal` feat: `Trace` on `PyReverseSequenceIterator` feat: `Trace` on `PyTuple` `PyTupleIterator` `PyTupleTyped` feat: `Trace` on `PyFilter` `PyFunction` `PyBoundMethod` feat: `Trace` on `PyCell` feat: `Trace` on `PyList` `PyListIterator` `PyListReverseIterator` feat: `Trace` on `PyMap` `PyMappingProxy` `MappingProxyInner` feat: `Trace` on PyMemoryViewNewArgs, PyMemoryViewIterator feat: `Trace` on PyProperty, PySet, PySetInner feat: `Trace` on PySlice, PyStaticMethod feat: `Trace` on FuncArgs, KwArgs, PosArgs, OptionalArg feat: `Trace` on PySuper, PySuperNewArgs feat: `Trace` on `PyTraceback` feat: `Trace` for PyBaseException, PyType, PyUnion feat: `Trace` on PyWeakProxy, PyZip, PyBuffer feat: `Trace` on PyMapping, PyNumber, PySequence feat: add `list_traceable` macro fix: right lifetime for `TracerFn` feat: `trace` PyObjectRef&PyRef feat: garbage cycle collector fix: put drop_only in different loop feat: core algorithm of garbage collect feat: add drop_only&dealloc_only to vtable feat: modify core.rs to use gc style: cargo fmt feat: add `try_gc`& gc per frame feat: add `collect` in gc module fix: set black when safe_inc fix: check if is gc-ing in `should_gc` refactor: cfg(gc) for `Drop` trait fix: not add to roots multiple times fix: add judge for if dropped doc: add TODO fix: prevent dealloc cycle garbage early fix: `partially_drop` header later fix: add dealloc guard for deref fix: run `__del__`&drop separately feat: more lock to gc&drop check feat: make gc less freq fix: cfg compile&support attr in partially_drop feat: `pytrace` macro feat: use `#[pytrace]` in some types feat: compact header feat: change gc cond to 10007 obj cnts fix: trace `PyRange` fix: drop ref vtable before dealloc to prevent UB fix: debug check&cfg cond&clippy fix: add ref only after `__del__` is done feat: trace(unsafely ) PyMutex feat: prevent trace PyMutex when not gc feat: change `PyRwlock` back to `PyMutex` fix: testcase test_reference_loop test_unique_composite refactor: early exit of collect_cycles fix: cfg cond feat: gc pause warn msg when wait too long fix: not run __del__ in cycles fix: expected failure for test_unique_composite fix: allow test_ioctl_signed_unsigned_code_param feat: split `drop` to `del`&`weakref` fix: lock cond fix: pause cond so high freq gc not halt all refactor: put impl Collector together feat: drop weak_list later feat: unlock gc pause lock fairly feat: print progress for two long test feat: adjust lock order¬ panic fix: let obj handle its weakref's dealloc fix: check stack before pop fix: not leak weakref log: remove some false alarm fix: cfg flag for cond compile fix: cfg flag for no-default-feature fix: use non-block incref test: change gc to 1ms&exit all if wait too long fix: INCREF done right¬ gc until last gc done feat: add `gc` feature to root crate doc: TODO for PEP442 del in cycle fix: temporaily add one more `gc.collect()` test: add gc feature in CI refactor: make `mark/scan_roots` associated fn refactor: `free_cycles` fn test: flush progress prompt docs: add TODO for modified testcases refactor: header state's type feat: drop_only log: gc info clippy: drop_only allow unused refactor: rename `gc` feature to `gc_bacon` refactor: remove `allow(unused)` feat: `MaybeTrace` trait feat: add `trace` Meta for `pyclass` proc macro feat: cfg cond flag for `MaybeTrace` feat: add `trace` in vtable fix: add`#[pyclass(trace)` for manual impl trace fix: elide null check in vtable&CR refactor fix: change name in CI tests feat: not use gc in wasm refactor: accord to Code Review doc&fix: explain gc&fix macro fix: test_sys_setprofile
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| use proc_macro2::TokenStream; | ||
| use quote::quote; | ||
| use syn::{AttributeArgs, DeriveInput, Result}; | ||
|
|
||
| /// also remove `#[notrace]` attr, and not trace corresponding field | ||
| fn gen_trace_code(item: &mut DeriveInput) -> Result<TokenStream> { | ||
| match &mut item.data { | ||
| syn::Data::Struct(s) => { | ||
| let fields = &mut s.fields; | ||
| if let syn::Fields::Named(ref mut fields) = fields { | ||
| let res: TokenStream = fields | ||
| .named | ||
| .iter_mut() | ||
| .map(|f| { | ||
| let name = f | ||
| .ident | ||
| .as_ref() | ||
| .expect("Field should have a name in non-tuple struct"); | ||
| let mut do_trace = true; | ||
| f.attrs.retain(|attr| { | ||
| // remove #[notrace] and not trace this specifed field | ||
| if attr.path.segments.last().unwrap().ident == "notrace" { | ||
| do_trace = false; | ||
| false | ||
| } else { | ||
| true | ||
| } | ||
| }); | ||
| if do_trace { | ||
| quote!( | ||
| ::rustpython_vm::object::Trace::trace(&self.#name, tracer_fn); | ||
| ) | ||
| } else { | ||
| quote!() | ||
| } | ||
| }) | ||
| .collect(); | ||
| Ok(res) | ||
| } else { | ||
| panic!("Expect only Named fields") | ||
| } | ||
| } | ||
| syn::Data::Enum(_) => todo!(), | ||
| syn::Data::Union(_) => todo!(), | ||
| } | ||
| } | ||
|
|
||
| pub(crate) fn impl_pytrace(attr: AttributeArgs, mut item: DeriveInput) -> Result<TokenStream> { | ||
| if !attr.is_empty() { | ||
| panic!( | ||
| "pytrace macro expect no attr(s), found {} attr(s)", | ||
| attr.len() | ||
| ); | ||
| } | ||
|
|
||
| let trace_code = gen_trace_code(&mut item)?; | ||
|
|
||
| let ty = &item.ident; | ||
|
|
||
| let ret = quote! { | ||
| #item | ||
| #[cfg(feature = "gc_bacon")] | ||
| unsafe impl ::rustpython_vm::object::Trace for #ty { | ||
| fn trace(&self, tracer_fn: &mut ::rustpython_vm::object::TracerFn) { | ||
| #trace_code | ||
| } | ||
| } | ||
| }; | ||
| Ok(ret) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -91,3 +91,20 @@ pub fn pypayload(input: TokenStream) -> TokenStream { | |
| let input = parse_macro_input!(input); | ||
| derive_impl::pypayload(input).into() | ||
| } | ||
|
|
||
| /// use on struct with named fields like `struct A{x:i32, y:i32}` to impl `Trace` for datatype | ||
| /// | ||
| /// use `#[notrace]` on fields you wish not to trace | ||
| /// | ||
| /// add `trace` attr to `#[pyclass]` to make it | ||
| /// traceable(Even from type-erased PyObject)(i.e. write `#[pyclass(trace)]`) | ||
| /// better to place after `#[pyclass]` so pyclass know `pytrace`'s existance and impl a MaybeTrace calling Trace | ||
| #[proc_macro_attribute] | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could probably be a normal derive() macro, and then you wouldn't have to deal with removing the notrace attr
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, |
||
| pub fn pytrace( | ||
| attr: proc_macro::TokenStream, | ||
| item: proc_macro::TokenStream, | ||
| ) -> proc_macro::TokenStream { | ||
| let attr = parse_macro_input!(attr); | ||
| let item = parse_macro_input!(item); | ||
| derive_impl::pytrace(attr, item).into() | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,22 +6,52 @@ mod gc { | |
|
|
||
| #[pyfunction] | ||
| fn collect(_args: FuncArgs, _vm: &VirtualMachine) -> i32 { | ||
| 0 | ||
| #[cfg(feature = "gc_bacon")] | ||
| { | ||
| usize::from(rustpython_vm::object::collect()) as i32 | ||
| } | ||
| #[cfg(not(feature = "gc_bacon"))] | ||
| { | ||
| 0 | ||
| } | ||
| } | ||
|
|
||
| #[pyfunction] | ||
| fn isenabled(_args: FuncArgs, _vm: &VirtualMachine) -> bool { | ||
| false | ||
| #[cfg(feature = "gc_bacon")] | ||
| { | ||
| rustpython_vm::object::isenabled() | ||
| } | ||
| #[cfg(not(feature = "gc_bacon"))] | ||
| { | ||
| false | ||
| } | ||
| } | ||
|
|
||
| #[pyfunction] | ||
| fn enable(_args: FuncArgs, vm: &VirtualMachine) -> PyResult { | ||
| Err(vm.new_not_implemented_error("".to_owned())) | ||
| #[cfg(feature = "gc_bacon")] | ||
| { | ||
| rustpython_vm::object::enable(); | ||
| Ok(vm.new_pyobj(true)) | ||
| } | ||
| #[cfg(not(feature = "gc_bacon"))] | ||
| { | ||
| Err(vm.new_not_implemented_error("".to_owned())) | ||
| } | ||
| } | ||
|
|
||
| #[pyfunction] | ||
| fn disable(_args: FuncArgs, vm: &VirtualMachine) -> PyResult { | ||
| Err(vm.new_not_implemented_error("".to_owned())) | ||
| #[cfg(feature = "gc_bacon")] | ||
| { | ||
| rustpython_vm::object::disable(); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be good for these to have more descriptive names, either a
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Indeed, in CPython, the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
how about "gc_bacon" as feature name(as bacon is the papers' author)? |
||
| Ok(vm.new_pyobj(true)) | ||
| } | ||
| #[cfg(not(feature = "gc_bacon"))] | ||
| { | ||
| Err(vm.new_not_implemented_error("".to_owned())) | ||
| } | ||
| } | ||
|
|
||
| #[pyfunction] | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.