Skip to content

Commit 7c134bb

Browse files
committed
[Java.Interop] Prevent premature collection w/ JniInstance*
Context: dotnet/android@e88cfbc While writing the commit message for xamarin/xamarin-android/@e88cfbcf, it occurred to me that the same fundamental scenario of: CallIntoJava (new JavaLangObjectSubclass ().Handle); // GC collects instance after `.Handle`, before `CallIntoJava()` could apply to `JniPeerMembers.JniInstanceMethods.Invoke*()` invocations: JniArgumentValue* __args = …; _members.InstanceMethods.InvokeVirtualObjectMethod (__id, this, __args); // What prevents `this` from being collected "too soon"? Address this: update `JniPeerMembers.JniInstanceMethods.Invoke*()` so that there is a `GC.KeepAlive(self)` after accessing `self.PeerReference`. This will ensure that `self` isn't collected "during" `JniEnvironment.InstanceMethods.Call*Method()` invocations. Likewise update `JniPeerMembers.JniInstanceFields.Get*Value()` and `JniPeerMembers.JniInstanceFields.Set*Value()` so that there is a `GC.KeepAlive(self)` after the `JniEnvironment.InstanceFields.*` invocation.
1 parent 876442f commit 7c134bb

File tree

4 files changed

+142
-90
lines changed

4 files changed

+142
-90
lines changed

src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.cs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ public bool GetBooleanValue (
1212
JniPeerMembers.AssertSelf (self);
1313

1414
var f = GetFieldInfo (encodedMember);
15-
return JniEnvironment.InstanceFields.GetBooleanField (self.PeerReference, f);
15+
var r = JniEnvironment.InstanceFields.GetBooleanField (self.PeerReference, f);
16+
GC.KeepAlive (self);
17+
return r;
1618
}
1719

1820
public void SetValue (string encodedMember, IJavaPeerable self, bool value)
@@ -21,6 +23,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, bool value)
2123

2224
var f = GetFieldInfo (encodedMember);
2325
JniEnvironment.InstanceFields.SetBooleanField (self.PeerReference, f, value);
26+
GC.KeepAlive (self);
2427
}
2528

2629
public sbyte GetSByteValue (
@@ -30,7 +33,9 @@ public sbyte GetSByteValue (
3033
JniPeerMembers.AssertSelf (self);
3134

3235
var f = GetFieldInfo (encodedMember);
33-
return JniEnvironment.InstanceFields.GetByteField (self.PeerReference, f);
36+
var r = JniEnvironment.InstanceFields.GetByteField (self.PeerReference, f);
37+
GC.KeepAlive (self);
38+
return r;
3439
}
3540

3641
public void SetValue (string encodedMember, IJavaPeerable self, sbyte value)
@@ -39,6 +44,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, sbyte value)
3944

4045
var f = GetFieldInfo (encodedMember);
4146
JniEnvironment.InstanceFields.SetByteField (self.PeerReference, f, value);
47+
GC.KeepAlive (self);
4248
}
4349

4450
public char GetCharValue (
@@ -48,7 +54,9 @@ public char GetCharValue (
4854
JniPeerMembers.AssertSelf (self);
4955

5056
var f = GetFieldInfo (encodedMember);
51-
return JniEnvironment.InstanceFields.GetCharField (self.PeerReference, f);
57+
var r = JniEnvironment.InstanceFields.GetCharField (self.PeerReference, f);
58+
GC.KeepAlive (self);
59+
return r;
5260
}
5361

5462
public void SetValue (string encodedMember, IJavaPeerable self, char value)
@@ -57,6 +65,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, char value)
5765

5866
var f = GetFieldInfo (encodedMember);
5967
JniEnvironment.InstanceFields.SetCharField (self.PeerReference, f, value);
68+
GC.KeepAlive (self);
6069
}
6170

6271
public short GetInt16Value (
@@ -66,7 +75,9 @@ public short GetInt16Value (
6675
JniPeerMembers.AssertSelf (self);
6776

6877
var f = GetFieldInfo (encodedMember);
69-
return JniEnvironment.InstanceFields.GetShortField (self.PeerReference, f);
78+
var r = JniEnvironment.InstanceFields.GetShortField (self.PeerReference, f);
79+
GC.KeepAlive (self);
80+
return r;
7081
}
7182

7283
public void SetValue (string encodedMember, IJavaPeerable self, short value)
@@ -75,6 +86,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, short value)
7586

7687
var f = GetFieldInfo (encodedMember);
7788
JniEnvironment.InstanceFields.SetShortField (self.PeerReference, f, value);
89+
GC.KeepAlive (self);
7890
}
7991

8092
public int GetInt32Value (
@@ -84,7 +96,9 @@ public int GetInt32Value (
8496
JniPeerMembers.AssertSelf (self);
8597

8698
var f = GetFieldInfo (encodedMember);
87-
return JniEnvironment.InstanceFields.GetIntField (self.PeerReference, f);
99+
var r = JniEnvironment.InstanceFields.GetIntField (self.PeerReference, f);
100+
GC.KeepAlive (self);
101+
return r;
88102
}
89103

90104
public void SetValue (string encodedMember, IJavaPeerable self, int value)
@@ -93,6 +107,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, int value)
93107

94108
var f = GetFieldInfo (encodedMember);
95109
JniEnvironment.InstanceFields.SetIntField (self.PeerReference, f, value);
110+
GC.KeepAlive (self);
96111
}
97112

98113
public long GetInt64Value (
@@ -102,7 +117,9 @@ public long GetInt64Value (
102117
JniPeerMembers.AssertSelf (self);
103118

104119
var f = GetFieldInfo (encodedMember);
105-
return JniEnvironment.InstanceFields.GetLongField (self.PeerReference, f);
120+
var r = JniEnvironment.InstanceFields.GetLongField (self.PeerReference, f);
121+
GC.KeepAlive (self);
122+
return r;
106123
}
107124

108125
public void SetValue (string encodedMember, IJavaPeerable self, long value)
@@ -111,6 +128,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, long value)
111128

112129
var f = GetFieldInfo (encodedMember);
113130
JniEnvironment.InstanceFields.SetLongField (self.PeerReference, f, value);
131+
GC.KeepAlive (self);
114132
}
115133

116134
public float GetSingleValue (
@@ -120,7 +138,9 @@ public float GetSingleValue (
120138
JniPeerMembers.AssertSelf (self);
121139

122140
var f = GetFieldInfo (encodedMember);
123-
return JniEnvironment.InstanceFields.GetFloatField (self.PeerReference, f);
141+
var r = JniEnvironment.InstanceFields.GetFloatField (self.PeerReference, f);
142+
GC.KeepAlive (self);
143+
return r;
124144
}
125145

126146
public void SetValue (string encodedMember, IJavaPeerable self, float value)
@@ -129,6 +149,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, float value)
129149

130150
var f = GetFieldInfo (encodedMember);
131151
JniEnvironment.InstanceFields.SetFloatField (self.PeerReference, f, value);
152+
GC.KeepAlive (self);
132153
}
133154

134155
public double GetDoubleValue (
@@ -138,7 +159,9 @@ public double GetDoubleValue (
138159
JniPeerMembers.AssertSelf (self);
139160

140161
var f = GetFieldInfo (encodedMember);
141-
return JniEnvironment.InstanceFields.GetDoubleField (self.PeerReference, f);
162+
var r = JniEnvironment.InstanceFields.GetDoubleField (self.PeerReference, f);
163+
GC.KeepAlive (self);
164+
return r;
142165
}
143166

144167
public void SetValue (string encodedMember, IJavaPeerable self, double value)
@@ -147,6 +170,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, double value)
147170

148171
var f = GetFieldInfo (encodedMember);
149172
JniEnvironment.InstanceFields.SetDoubleField (self.PeerReference, f, value);
173+
GC.KeepAlive (self);
150174
}
151175

152176
public JniObjectReference GetObjectValue (
@@ -156,7 +180,9 @@ public JniObjectReference GetObjectValue (
156180
JniPeerMembers.AssertSelf (self);
157181

158182
var f = GetFieldInfo (encodedMember);
159-
return JniEnvironment.InstanceFields.GetObjectField (self.PeerReference, f);
183+
var r = JniEnvironment.InstanceFields.GetObjectField (self.PeerReference, f);
184+
GC.KeepAlive (self);
185+
return r;
160186
}
161187

162188
public void SetValue (string encodedMember, IJavaPeerable self, JniObjectReference value)
@@ -165,6 +191,7 @@ public void SetValue (string encodedMember, IJavaPeerable self, JniObjectReferen
165191

166192
var f = GetFieldInfo (encodedMember);
167193
JniEnvironment.InstanceFields.SetObjectField (self.PeerReference, f, value);
194+
GC.KeepAlive (self);
168195
}
169196
}
170197

src/Java.Interop/Java.Interop/JniPeerMembers.JniFields.tt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ namespace Java.Interop {
3434
JniPeerMembers.AssertSelf (self);
3535

3636
var f = GetFieldInfo (encodedMember);
37-
return JniEnvironment.InstanceFields.Get<#= info.JniCallType #>Field (self.PeerReference, f);
37+
var r = JniEnvironment.InstanceFields.Get<#= info.JniCallType #>Field (self.PeerReference, f);
38+
GC.KeepAlive (self);
39+
return r;
3840
}
3941

4042
public void SetValue (string encodedMember, IJavaPeerable self, <#= info.ParameterType #> value)
@@ -43,6 +45,7 @@ namespace Java.Interop {
4345

4446
var f = GetFieldInfo (encodedMember);
4547
JniEnvironment.InstanceFields.Set<#= info.JniCallType #>Field (self.PeerReference, f, value);
48+
GC.KeepAlive (self);
4649
}
4750
<#
4851
}

0 commit comments

Comments
 (0)