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 "art_method-inl.h"
18#include "entrypoints/entrypoint_utils-inl.h"
19#include "mirror/object-inl.h"
20#include "thread-inl.h"
21#include "verify_object-inl.h"
22
23namespace art {
24
25extern void ReadBarrierJni(mirror::CompressedReference<mirror::Object>* handle_on_stack,
26                           Thread* self ATTRIBUTE_UNUSED) {
27  // Call the read barrier and update the handle.
28  mirror::Object* to_ref = ReadBarrier::BarrierForRoot(handle_on_stack);
29  handle_on_stack->Assign(to_ref);
30}
31
32// Called on entry to JNI, transition out of Runnable and release share of mutator_lock_.
33extern uint32_t JniMethodStart(Thread* self) {
34  JNIEnvExt* env = self->GetJniEnv();
35  DCHECK(env != nullptr);
36  uint32_t saved_local_ref_cookie = env->local_ref_cookie;
37  env->local_ref_cookie = env->locals.GetSegmentState();
38  ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
39  if (!native_method->IsFastNative()) {
40    // When not fast JNI we transition out of runnable.
41    self->TransitionFromRunnableToSuspended(kNative);
42  }
43  return saved_local_ref_cookie;
44}
45
46extern uint32_t JniMethodStartSynchronized(jobject to_lock, Thread* self) {
47  self->DecodeJObject(to_lock)->MonitorEnter(self);
48  return JniMethodStart(self);
49}
50
51// TODO: NO_THREAD_SAFETY_ANALYSIS due to different control paths depending on fast JNI.
52static void GoToRunnable(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
53  ArtMethod* native_method = *self->GetManagedStack()->GetTopQuickFrame();
54  bool is_fast = native_method->IsFastNative();
55  if (!is_fast) {
56    self->TransitionFromSuspendedToRunnable();
57  } else if (UNLIKELY(self->TestAllFlags())) {
58    // In fast JNI mode we never transitioned out of runnable. Perform a suspend check if there
59    // is a flag raised.
60    DCHECK(Locks::mutator_lock_->IsSharedHeld(self));
61    self->CheckSuspend();
62  }
63}
64
65static void PopLocalReferences(uint32_t saved_local_ref_cookie, Thread* self)
66    SHARED_REQUIRES(Locks::mutator_lock_) {
67  JNIEnvExt* env = self->GetJniEnv();
68  if (UNLIKELY(env->check_jni)) {
69    env->CheckNoHeldMonitors();
70  }
71  env->locals.SetSegmentState(env->local_ref_cookie);
72  env->local_ref_cookie = saved_local_ref_cookie;
73  self->PopHandleScope();
74}
75
76extern void JniMethodEnd(uint32_t saved_local_ref_cookie, Thread* self) {
77  GoToRunnable(self);
78  PopLocalReferences(saved_local_ref_cookie, self);
79}
80
81extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked,
82                                     Thread* self) {
83  GoToRunnable(self);
84  UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
85  PopLocalReferences(saved_local_ref_cookie, self);
86}
87
88// Common result handling for EndWithReference.
89static mirror::Object* JniMethodEndWithReferenceHandleResult(jobject result,
90                                                             uint32_t saved_local_ref_cookie,
91                                                             Thread* self)
92    NO_THREAD_SAFETY_ANALYSIS {
93  // Must decode before pop. The 'result' may not be valid in case of an exception, though.
94  mirror::Object* o = self->IsExceptionPending() ? nullptr : self->DecodeJObject(result);
95  PopLocalReferences(saved_local_ref_cookie, self);
96  // Process result.
97  if (UNLIKELY(self->GetJniEnv()->check_jni)) {
98    CheckReferenceResult(o, self);
99  }
100  VerifyObject(o);
101  return o;
102}
103
104extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
105                                                 Thread* self) {
106  GoToRunnable(self);
107  return JniMethodEndWithReferenceHandleResult(result, saved_local_ref_cookie, self);
108}
109
110extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result,
111                                                             uint32_t saved_local_ref_cookie,
112                                                             jobject locked, Thread* self) {
113  GoToRunnable(self);
114  UnlockJniSynchronizedMethod(locked, self);
115  return JniMethodEndWithReferenceHandleResult(result, saved_local_ref_cookie, self);
116}
117
118extern uint64_t GenericJniMethodEnd(Thread* self,
119                                    uint32_t saved_local_ref_cookie,
120                                    jvalue result,
121                                    uint64_t result_f,
122                                    ArtMethod* called,
123                                    HandleScope* handle_scope)
124    // TODO: NO_THREAD_SAFETY_ANALYSIS as GoToRunnable() is NO_THREAD_SAFETY_ANALYSIS
125    NO_THREAD_SAFETY_ANALYSIS {
126  GoToRunnable(self);
127  // We need the mutator lock (i.e., calling GoToRunnable()) before accessing the shorty or the
128  // locked object.
129  jobject locked = called->IsSynchronized() ? handle_scope->GetHandle(0).ToJObject() : nullptr;
130  char return_shorty_char = called->GetShorty()[0];
131  if (return_shorty_char == 'L') {
132    if (locked != nullptr) {
133      UnlockJniSynchronizedMethod(locked, self);
134    }
135    return reinterpret_cast<uint64_t>(JniMethodEndWithReferenceHandleResult(
136        result.l, saved_local_ref_cookie, self));
137  } else {
138    if (locked != nullptr) {
139      UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
140    }
141    PopLocalReferences(saved_local_ref_cookie, self);
142    switch (return_shorty_char) {
143      case 'F': {
144        if (kRuntimeISA == kX86) {
145          // Convert back the result to float.
146          double d = bit_cast<double, uint64_t>(result_f);
147          return bit_cast<uint32_t, float>(static_cast<float>(d));
148        } else {
149          return result_f;
150        }
151      }
152      case 'D':
153        return result_f;
154      case 'Z':
155        return result.z;
156      case 'B':
157        return result.b;
158      case 'C':
159        return result.c;
160      case 'S':
161        return result.s;
162      case 'I':
163        return result.i;
164      case 'J':
165        return result.j;
166      case 'V':
167        return 0;
168      default:
169        LOG(FATAL) << "Unexpected return shorty character " << return_shorty_char;
170        return 0;
171    }
172  }
173}
174
175}  // namespace art
176