From 8c26f2ecf226f7d16a48f7a94006b801e609c3ee Mon Sep 17 00:00:00 2001 From: Jamieson Pryor Date: Mon, 26 Jun 2023 17:58:08 -0700 Subject: [PATCH] Fix broken promotion mechanics for richly decorated locals to globals. **THIS IS A BREAKING CHANGE** Locals were being blindly absorbed by globals which is wrong. Clients are unlikely to be broken because this logic would cause crashes on use, however, I can't guarantee there isn't a path that relied on this. PiperOrigin-RevId: 543592694 --- implementation/global_object_test.cc | 29 ++++++++++++++++++++++++++-- implementation/promotion_mechanics.h | 28 +++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/implementation/global_object_test.cc b/implementation/global_object_test.cc index dcff448f..2da5c013 100644 --- a/implementation/global_object_test.cc +++ b/implementation/global_object_test.cc @@ -30,6 +30,7 @@ using ::jni::Constructor; using ::jni::CreateCopy; using ::jni::Field; using ::jni::GlobalObject; +using ::jni::LocalObject; using ::jni::Method; using ::jni::Params; using ::jni::PromoteToGlobal; @@ -75,7 +76,7 @@ TEST_F(JniTest, GlobalObject_DoesNotDeleteAnyLocalsForAdoptedGlobalJobject) { GlobalObject global_object{AdoptGlobal{}, Fake()}; - EXPECT_NE(jobject{global_object}, nullptr); + EXPECT_EQ(jobject{global_object}, Fake()); } TEST_F(JniTest, GlobalObject_PromotesJobjectsOnConstruction) { @@ -85,8 +86,32 @@ TEST_F(JniTest, GlobalObject_PromotesJobjectsOnConstruction) { static constexpr Class kClass{"kClass"}; GlobalObject global_object{PromoteToGlobal{}, Fake()}; + EXPECT_EQ(jobject{global_object}, AsGlobal(Fake())); +} - EXPECT_NE(jobject{global_object}, nullptr); +TEST_F(JniTest, GlobalObject_PromotesDecoratedLocals) { + EXPECT_CALL(*env_, NewObjectV).Times(0); + EXPECT_CALL(*env_, DeleteLocalRef).Times(1); + EXPECT_CALL(*env_, DeleteGlobalRef(AsGlobal(Fake()))); + + static constexpr Class kClass{"kClass"}; + LocalObject local_obj{Fake()}; + // GlobalObject global_object{local_obj}; // doesn't compile (good). + GlobalObject global_object{std::move(local_obj)}; + + EXPECT_EQ(jobject{global_object}, AsGlobal(Fake())); +} + +// Identical to above but Local constructed in place. +TEST_F(JniTest, GlobalObject_PromotesDecoratedLocalsFromXValue) { + EXPECT_CALL(*env_, NewObjectV).Times(0); + EXPECT_CALL(*env_, DeleteLocalRef).Times(1); + EXPECT_CALL(*env_, DeleteGlobalRef(AsGlobal(Fake()))); + + static constexpr Class kClass{"kClass"}; + GlobalObject global_object{LocalObject{Fake()}}; + + EXPECT_EQ(jobject{global_object}, AsGlobal(Fake())); } TEST_F(JniTest, GlobalObject_CallsOnlyDeleteOnWrapCtor) { diff --git a/implementation/promotion_mechanics.h b/implementation/promotion_mechanics.h index 63267e66..9287c4c6 100644 --- a/implementation/promotion_mechanics.h +++ b/implementation/promotion_mechanics.h @@ -43,8 +43,7 @@ struct AdoptGlobal {}; // Marks the end of `ScopeEntry` daisy chain. struct ScopedTerminalTag {}; -// Shared implementation common to all `Entry`. -// template +// Shared implementation common to all *local* `Entry`. template struct EntryBase : public Base { @@ -52,9 +51,9 @@ struct EntryBase : public Base { using Span = typename JniT::SpanType; // `RefBaseTag` move constructor for object of same span type. - template || - std::is_base_of_v, T>>> + std::is_base_of_v, T>)>> EntryBase(T&& rhs) : Base(rhs.Release()) {} // "Copy" constructor: Additional reference to object will be created. @@ -79,6 +78,27 @@ struct Entry : Base(static_cast(object)) {} }; +// Shared implementation common to all *global* `Entry`. +template +struct EntryBase : public Base { + using Base::Base; + using Span = typename JniT::SpanType; + + // `RefBaseTag` move constructor for object of same span type. + template || + std::is_base_of_v, T>)>> + EntryBase(T&& rhs) + : Base(LifecycleHelper::Promote(rhs.Release())) {} + + // "Copy" constructor: Additional reference to object will be created. + EntryBase(CreateCopy, ViableSpan object) + : Base(static_cast( + LifecycleHelper::NewReference( + static_cast(object)))) {} +}; + // Global scoped entry augmentation. template struct Entry