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

Preserved list refactor #92

Merged
merged 11 commits into from Sep 11, 2020
Merged

Conversation

bkietz
Copy link
Collaborator

@bkietz bkietz commented Aug 15, 2020

  • Renamed from protect_sexp/release_protect/... to preserved.insert/preserved.release to highlight the similarity in intent to R_PreserveObject and decrease the semantic overload of "protect"
  • Moved the doubly-linked list of preserved objects from a static object in c++ named cpp11::protect_list to an internal in R named cpp11:::.preserve_list. This allows the list to be a singleton since any shared object we load will look up the same cpp11:::.preserve_list. By contrast a new c++ static variable will be instantiated for each translation unit we compile, resulting in multiple unrelated preserve_lists:
    cpp11::cpp_function('SEXP protect_one(SEXP e) { cpp11::protect_sexp(e); return e; }')
    cpp11::cpp_function('int protected_count() { return Rf_length(cpp11::protect_list) - 1; }')
    for (i in 1:10) protect_one(i)
    protected_count() # 0, since it comes from a different translation unit from protect_one
  • Inlined cpp11::preserve()
  • sexp& sexp::operator=(const sexp& rhs) did not release its data before acquiring a new preservation token

@bkietz bkietz requested a review from jimhester August 15, 2020 21:54
@bkietz
Copy link
Collaborator Author

bkietz commented Aug 16, 2020

"testing if installed package can be loaded from temporary location" failed with cpp11:::.preserve_list because the cpp11 namespace doesn't exist for that step. My first approach to resolve this was to try to create that namespace from c++ when it isn't found. I can't figure out how to do that, so for now I just dump .cpp11_preserve_list into the global env. There's probably a better way

@jimhester
Copy link
Member

One issue with this approach and part of the reason I didn't mind having multiple protect lists for each compilation unit is currently there is no requirement for the cpp11 package itself to be loaded.

An alternative would be to create the protect list in the init function in the generated code. This would give us one protect list per loaded R package that uses cpp11.

extern "C" void R_init_cpp11test(DllInfo* dll){

@bkietz
Copy link
Collaborator Author

bkietz commented Aug 17, 2020

With multiple protect lists, release_existing_protections() only applies to some protections. If that's intentional then we should document the subtlety; in interactive use one might write

cpp11::cpp_function('int release_all() {
  int n = Rf_length(cpp11::protect_list) - 1;
  cpp11::release_existing_protections();
  return n;
}')

which wouldn't have the desired effect.

@jimhester
Copy link
Member

Yeah, though code needing to manually call release_existing_protections() should be pretty rare in practice, it is only needed on older R versions.

Creating the list as an object in the actual R_GlobalEnv is likely against CRAN policies, and as mentioned the cpp11 package is not guaranteed to be loaded (and usually won't be) by dependent packages, so we can't put it in the cpp11 package namespace environment. I think the best we could do is create it in the initialization code, which will give us one protection list for each shared library that uses cpp11.

Rather than an object in the global environment.

Using an option is consistent with CRAN policies, whereas it is
against policy for a package to modify the global environment
@jimhester
Copy link
Member

I just thought of a way to do this that will give us a singleton and is not against CRAN policies.

Setting package specific global options are allowed by CRAN, so we could store the preserve list there.

I did this in 9c5dd15

@jimhester
Copy link
Member

Unfortunately there seems to be something wrong with the implementation, we are getting an error on the CI with R 3.4 (https://github.com/r-lib/cpp11/pull/92/checks?check_run_id=1086545888#step:15:15)

protect(): protection stack overflow

And I see the same error with some of the tests in vroom with this PR.

I am still trying to track down the issue.

Instead of directly, since `options()` and `getOption()` call
`duplicate()` on their return, and if we try to duplicate the pairlist
we run into errors.
@jimhester
Copy link
Member

Ok so the issue was due to option values being duplicated by the options() function. Putting the preserve list in an environment avoids this issue and should resolve the errors.

@jimhester jimhester marked this pull request as ready for review September 10, 2020 13:55
@jimhester
Copy link
Member

I think this is all working now, @bkietz if you have time to review my changes I can merge this.

inst/include/cpp11/list.hpp Outdated Show resolved Hide resolved
inst/include/cpp11/raws.hpp Outdated Show resolved Hide resolved
inst/include/cpp11/strings.hpp Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants