1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/logging.h>
18 
19 #include "art_method-inl.h"
20 #include "base/casts.h"
21 #include "entrypoints/entrypoint_utils-inl.h"
22 #include "indirect_reference_table.h"
23 #include "mirror/object-inl.h"
24 #include "palette/palette.h"
25 #include "thread-inl.h"
26 #include "verify_object.h"
27 
28 // For methods that monitor JNI invocations and report their begin/end to
29 // palette hooks.
30 #define MONITOR_JNI(kind)                                \
31   {                                                      \
32     bool should_report = false;                          \
33     PaletteShouldReportJniInvocations(&should_report);   \
34     if (should_report) {                                 \
35       kind(self->GetJniEnv());                           \
36     }                                                    \
37   }
38 
39 namespace art {
40 
41 static_assert(sizeof(IRTSegmentState) == sizeof(uint32_t), "IRTSegmentState size unexpected");
42 static_assert(std::is_trivial<IRTSegmentState>::value, "IRTSegmentState not trivial");
43 
44 static inline void GoToRunnableFast(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
45 
ReadBarrierJni(mirror::CompressedReference<mirror::Class> * declaring_class,Thread * self ATTRIBUTE_UNUSED)46 extern void ReadBarrierJni(mirror::CompressedReference<mirror::Class>* declaring_class,
47                            Thread* self ATTRIBUTE_UNUSED) {
48   DCHECK(kUseReadBarrier);
49   if (kUseBakerReadBarrier) {
50     DCHECK(declaring_class->AsMirrorPtr() != nullptr)
51         << "The class of a static jni call must not be null";
52     // Check the mark bit and return early if it's already marked.
53     if (LIKELY(declaring_class->AsMirrorPtr()->GetMarkBit() != 0)) {
54       return;
55     }
56   }
57   // Call the read barrier and update the handle.
58   mirror::Class* to_ref = ReadBarrier::BarrierForRoot(declaring_class);
59   declaring_class->Assign(to_ref);
60 }
61 
62 // Called on entry to fast JNI, push a new local reference table only.
JniMethodFastStart(Thread * self)63 extern uint32_t JniMethodFastStart(Thread* self) {
64   JNIEnvExt* env = self->GetJniEnv();
65   DCHECK(env != nullptr);
66   uint32_t saved_local_ref_cookie = bit_cast<uint32_t>(env->GetLocalRefCookie());
67   env->SetLocalRefCookie(env->GetLocalsSegmentState());
68 
69   if (kIsDebugBuild) {
70     ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
71     CHECK(native_method->IsFastNative()) << native_method->PrettyMethod();
72   }
73 
74   return saved_local_ref_cookie;
75 }
76 
77 // Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
JniMethodStart(Thread * self)78 extern uint32_t JniMethodStart(Thread* self) {
79   JNIEnvExt* env = self->GetJniEnv();
80   DCHECK(env != nullptr);
81   uint32_t saved_local_ref_cookie = bit_cast<uint32_t>(env->GetLocalRefCookie());
82   env->SetLocalRefCookie(env->GetLocalsSegmentState());
83 
84   if (kIsDebugBuild) {
85     ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
86     CHECK(!native_method->IsFastNative()) << native_method->PrettyMethod();
87   }
88 
89   // Transition out of runnable.
90   self->TransitionFromRunnableToSuspended(kNative);
91   return saved_local_ref_cookie;
92 }
93 
JniMethodStartSynchronized(jobject to_lock,Thread * self)94 extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self) {
95   self->DecodeJObject(to_lock)->MonitorEnter(self);
96   return JniMethodStart(self);
97 }
98 
99 // TODO: NO_THREAD_SAFETY_ANALYSIS due to different control paths depending on fast JNI.
GoToRunnable(Thread * self)100 static void GoToRunnable(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
101   if (kIsDebugBuild) {
102     ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
103     CHECK(!native_method->IsFastNative()) << native_method->PrettyMethod();
104   }
105 
106   self->TransitionFromSuspendedToRunnable();
107 }
108 
GoToRunnableFast(Thread * self)109 ALWAYS_INLINE static inline void GoToRunnableFast(Thread* self) {
110   if (kIsDebugBuild) {
111     // Should only enter here if the method is @FastNative.
112     ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
113     CHECK(native_method->IsFastNative()) << native_method->PrettyMethod();
114   }
115 
116   // When we are in @FastNative, we are already Runnable.
117   // Only do a suspend check on the way out of JNI.
118   if (UNLIKELY(self->TestAllFlags())) {
119     // In fast JNI mode we never transitioned out of runnable. Perform a suspend check if there
120     // is a flag raised.
121     DCHECK(Locks::mutator_lock_->IsSharedHeld(self));
122     self->CheckSuspend();
123   }
124 }
125 
PopLocalReferences(uint32_t saved_local_ref_cookie,Thread * self)126 static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self)
127     REQUIRES_SHARED(Locks::mutator_lock_) {
128   JNIEnvExt* env = self->GetJniEnv();
129   if (UNLIKELY(env->IsCheckJniEnabled())) {
130     env->CheckNoHeldMonitors();
131   }
132   env->SetLocalSegmentState(env->GetLocalRefCookie());
133   env->SetLocalRefCookie(bit_cast<IRTSegmentState>(saved_local_ref_cookie));
134 }
135 
136 // TODO: annotalysis disabled as monitor semantics are maintained in Java code.
UnlockJniSynchronizedMethod(jobject locked,Thread * self)137 static inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
138     NO_THREAD_SAFETY_ANALYSIS REQUIRES(!Roles::uninterruptible_) {
139   // Save any pending exception over monitor exit call.
140   ObjPtr<mirror::Throwable> saved_exception = nullptr;
141   if (UNLIKELY(self->IsExceptionPending())) {
142     saved_exception = self->GetException();
143     self->ClearException();
144   }
145   // Decode locked object and unlock, before popping local references.
146   self->DecodeJObject(locked)->MonitorExit(self);
147   if (UNLIKELY(self->IsExceptionPending())) {
148     LOG(FATAL) << "Synchronized JNI code returning with an exception:\n"
149         << saved_exception->Dump()
150         << "\nEncountered second exception during implicit MonitorExit:\n"
151         << self->GetException()->Dump();
152   }
153   // Restore pending exception.
154   if (saved_exception != nullptr) {
155     self->SetException(saved_exception);
156   }
157 }
158 
159 // TODO: These should probably be templatized or macro-ized.
160 // Otherwise there's just too much repetitive boilerplate.
161 
JniMethodEnd(uint32_t saved_local_ref_cookie,Thread * self)162 extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) {
163   GoToRunnable(self);
164   PopLocalReferences(saved_local_ref_cookie, self);
165 }
166 
JniMethodFastEnd(uint32_t saved_local_ref_cookie,Thread * self)167 extern void JniMethodFastEnd(uint32_t saved_local_ref_cookie, Thread* self) {
168   GoToRunnableFast(self);
169   PopLocalReferences(saved_local_ref_cookie, self);
170 }
171 
JniMethodEndSynchronized(uint32_t saved_local_ref_cookie,jobject locked,Thread * self)172 extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie,
173                                      jobject locked,
174                                      Thread* self) {
175   GoToRunnable(self);
176   UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
177   PopLocalReferences(saved_local_ref_cookie, self);
178 }
179 
180 // Common result handling for EndWithReference.
JniMethodEndWithReferenceHandleResult(jobject result,uint32_t saved_local_ref_cookie,Thread * self)181 static mirror::Object* JniMethodEndWithReferenceHandleResult(jobject result,
182                                                              uint32_t saved_local_ref_cookie,
183                                                              Thread* self)
184     NO_THREAD_SAFETY_ANALYSIS {
185   // Must decode before pop. The 'result' may not be valid in case of an exception, though.
186   ObjPtr<mirror::Object> o;
187   if (!self->IsExceptionPending()) {
188     o = self->DecodeJObject(result);
189   }
190   PopLocalReferences(saved_local_ref_cookie, self);
191   // Process result.
192   if (UNLIKELY(self->GetJniEnv()->IsCheckJniEnabled())) {
193     // CheckReferenceResult can resolve types.
194     StackHandleScope<1> hs(self);
195     HandleWrapperObjPtr<mirror::Object> h_obj(hs.NewHandleWrapper(&o));
196     CheckReferenceResult(h_obj, self);
197   }
198   VerifyObject(o);
199   return o.Ptr();
200 }
201 
JniMethodFastEndWithReference(jobject result,uint32_t saved_local_ref_cookie,Thread * self)202 extern mirror::Object* JniMethodFastEndWithReference(jobject result,
203                                                      uint32_t saved_local_ref_cookie,
204                                                      Thread* self) {
205   GoToRunnableFast(self);
206   return JniMethodEndWithReferenceHandleResult(result, saved_local_ref_cookie, self);
207 }
208 
JniMethodEndWithReference(jobject result,uint32_t saved_local_ref_cookie,Thread * self)209 extern mirror::Object* JniMethodEndWithReference(jobject result,
210                                                  uint32_t saved_local_ref_cookie,
211                                                  Thread* self) {
212   GoToRunnable(self);
213   return JniMethodEndWithReferenceHandleResult(result, saved_local_ref_cookie, self);
214 }
215 
JniMethodEndWithReferenceSynchronized(jobject result,uint32_t saved_local_ref_cookie,jobject locked,Thread * self)216 extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result,
217                                                              uint32_t saved_local_ref_cookie,
218                                                              jobject locked,
219                                                              Thread* self) {
220   GoToRunnable(self);
221   UnlockJniSynchronizedMethod(locked, self);
222   return JniMethodEndWithReferenceHandleResult(result, saved_local_ref_cookie, self);
223 }
224 
GenericJniMethodEnd(Thread * self,uint32_t saved_local_ref_cookie,jvalue result,uint64_t result_f,ArtMethod * called)225 extern uint64_t GenericJniMethodEnd(Thread* self,
226                                     uint32_t saved_local_ref_cookie,
227                                     jvalue result,
228                                     uint64_t result_f,
229                                     ArtMethod* called)
230     // TODO: NO_THREAD_SAFETY_ANALYSIS as GoToRunnable() is NO_THREAD_SAFETY_ANALYSIS
231     NO_THREAD_SAFETY_ANALYSIS {
232   bool critical_native = called->IsCriticalNative();
233   bool fast_native = called->IsFastNative();
234   bool normal_native = !critical_native && !fast_native;
235 
236   // @CriticalNative does not do a state transition. @FastNative usually does not do a state
237   // transition either but it performs a suspend check that may do state transitions.
238   if (LIKELY(normal_native)) {
239     MONITOR_JNI(PaletteNotifyEndJniInvocation);
240     GoToRunnable(self);
241   } else if (fast_native) {
242     GoToRunnableFast(self);
243   }
244   // We need the mutator lock (i.e., calling GoToRunnable()) before accessing the shorty or the
245   // locked object.
246   if (called->IsSynchronized()) {
247     DCHECK(normal_native) << "@FastNative/@CriticalNative and synchronize is not supported";
248     jobject lock = GetGenericJniSynchronizationObject(self, called);
249     DCHECK(lock != nullptr);
250     UnlockJniSynchronizedMethod(lock, self);
251   }
252   char return_shorty_char = called->GetShorty()[0];
253   if (return_shorty_char == 'L') {
254     return reinterpret_cast<uint64_t>(JniMethodEndWithReferenceHandleResult(
255         result.l, saved_local_ref_cookie, self));
256   } else {
257     if (LIKELY(!critical_native)) {
258       PopLocalReferences(saved_local_ref_cookie, self);
259     }
260     switch (return_shorty_char) {
261       case 'F': {
262         if (kRuntimeISA == InstructionSet::kX86) {
263           // Convert back the result to float.
264           double d = bit_cast<double, uint64_t>(result_f);
265           return bit_cast<uint32_t, float>(static_cast<float>(d));
266         } else {
267           return result_f;
268         }
269       }
270       case 'D':
271         return result_f;
272       case 'Z':
273         return result.z;
274       case 'B':
275         return result.b;
276       case 'C':
277         return result.c;
278       case 'S':
279         return result.s;
280       case 'I':
281         return result.i;
282       case 'J':
283         return result.j;
284       case 'V':
285         return 0;
286       default:
287         LOG(FATAL) << "Unexpected return shorty character " << return_shorty_char;
288         UNREACHABLE();
289     }
290   }
291 }
292 
JniMonitoredMethodStart(Thread * self)293 extern uint32_t JniMonitoredMethodStart(Thread* self) {
294   uint32_t result = JniMethodStart(self);
295   MONITOR_JNI(PaletteNotifyBeginJniInvocation);
296   return result;
297 }
298 
JniMonitoredMethodStartSynchronized(jobject to_lock,Thread * self)299 extern uint32_t JniMonitoredMethodStartSynchronized(jobject to_lock, Thread* self) {
300   uint32_t result = JniMethodStartSynchronized(to_lock, self);
301   MONITOR_JNI(PaletteNotifyBeginJniInvocation);
302   return result;
303 }
304 
JniMonitoredMethodEnd(uint32_t saved_local_ref_cookie,Thread * self)305 extern void JniMonitoredMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) {
306   MONITOR_JNI(PaletteNotifyEndJniInvocation);
307   return JniMethodEnd(saved_local_ref_cookie, self);
308 }
309 
JniMonitoredMethodEndSynchronized(uint32_t saved_local_ref_cookie,jobject locked,Thread * self)310 extern void JniMonitoredMethodEndSynchronized(uint32_t saved_local_ref_cookie,
311                                              jobject locked,
312                                              Thread* self) {
313   MONITOR_JNI(PaletteNotifyEndJniInvocation);
314   return JniMethodEndSynchronized(saved_local_ref_cookie, locked, self);
315 }
316 
JniMonitoredMethodEndWithReference(jobject result,uint32_t saved_local_ref_cookie,Thread * self)317 extern mirror::Object* JniMonitoredMethodEndWithReference(jobject result,
318                                                           uint32_t saved_local_ref_cookie,
319                                                           Thread* self) {
320   MONITOR_JNI(PaletteNotifyEndJniInvocation);
321   return JniMethodEndWithReference(result, saved_local_ref_cookie, self);
322 }
323 
JniMonitoredMethodEndWithReferenceSynchronized(jobject result,uint32_t saved_local_ref_cookie,jobject locked,Thread * self)324 extern mirror::Object* JniMonitoredMethodEndWithReferenceSynchronized(
325     jobject result,
326     uint32_t saved_local_ref_cookie,
327     jobject locked,
328     Thread* self) {
329   MONITOR_JNI(PaletteNotifyEndJniInvocation);
330   return JniMethodEndWithReferenceSynchronized(result, saved_local_ref_cookie, locked, self);
331 }
332 
333 }  // namespace art
334