1 /*
2  * Copyright (C) 2011 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 "jni_env_ext.h"
18 
19 #include "check_jni.h"
20 #include "indirect_reference_table.h"
21 #include "java_vm_ext.h"
22 #include "jni_internal.h"
23 
24 namespace art {
25 
26 static constexpr size_t kMonitorsInitial = 32;  // Arbitrary.
27 static constexpr size_t kMonitorsMax = 4096;  // Arbitrary sanity check.
28 
29 static constexpr size_t kLocalsInitial = 64;  // Arbitrary.
30 
31 // Checking "locals" requires the mutator lock, but at creation time we're really only interested
32 // in validity, which isn't changing. To avoid grabbing the mutator lock, factored out and tagged
33 // with NO_THREAD_SAFETY_ANALYSIS.
CheckLocalsValid(JNIEnvExt * in)34 static bool CheckLocalsValid(JNIEnvExt* in) NO_THREAD_SAFETY_ANALYSIS {
35   if (in == nullptr) {
36     return false;
37   }
38   return in->locals.IsValid();
39 }
40 
Create(Thread * self_in,JavaVMExt * vm_in)41 JNIEnvExt* JNIEnvExt::Create(Thread* self_in, JavaVMExt* vm_in) {
42   std::unique_ptr<JNIEnvExt> ret(new JNIEnvExt(self_in, vm_in));
43   if (CheckLocalsValid(ret.get())) {
44     return ret.release();
45   }
46   return nullptr;
47 }
48 
JNIEnvExt(Thread * self_in,JavaVMExt * vm_in)49 JNIEnvExt::JNIEnvExt(Thread* self_in, JavaVMExt* vm_in)
50     : self(self_in),
51       vm(vm_in),
52       local_ref_cookie(IRT_FIRST_SEGMENT),
53       locals(kLocalsInitial, kLocalsMax, kLocal, false),
54       check_jni(false),
55       critical(0),
56       monitors("monitors", kMonitorsInitial, kMonitorsMax) {
57   functions = unchecked_functions = GetJniNativeInterface();
58   if (vm->IsCheckJniEnabled()) {
59     SetCheckJniEnabled(true);
60   }
61 }
62 
~JNIEnvExt()63 JNIEnvExt::~JNIEnvExt() {
64 }
65 
NewLocalRef(mirror::Object * obj)66 jobject JNIEnvExt::NewLocalRef(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
67   if (obj == nullptr) {
68     return nullptr;
69   }
70   return reinterpret_cast<jobject>(locals.Add(local_ref_cookie, obj));
71 }
72 
DeleteLocalRef(jobject obj)73 void JNIEnvExt::DeleteLocalRef(jobject obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
74   if (obj != nullptr) {
75     locals.Remove(local_ref_cookie, reinterpret_cast<IndirectRef>(obj));
76   }
77 }
78 
SetCheckJniEnabled(bool enabled)79 void JNIEnvExt::SetCheckJniEnabled(bool enabled) {
80   check_jni = enabled;
81   functions = enabled ? GetCheckJniNativeInterface() : GetJniNativeInterface();
82 }
83 
DumpReferenceTables(std::ostream & os)84 void JNIEnvExt::DumpReferenceTables(std::ostream& os) {
85   locals.Dump(os);
86   monitors.Dump(os);
87 }
88 
PushFrame(int capacity)89 void JNIEnvExt::PushFrame(int capacity) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
90   UNUSED(capacity);  // cpplint gets confused with (int) and thinks its a cast.
91   // TODO: take 'capacity' into account.
92   stacked_local_ref_cookies.push_back(local_ref_cookie);
93   local_ref_cookie = locals.GetSegmentState();
94 }
95 
PopFrame()96 void JNIEnvExt::PopFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
97   locals.SetSegmentState(local_ref_cookie);
98   local_ref_cookie = stacked_local_ref_cookies.back();
99   stacked_local_ref_cookies.pop_back();
100 }
101 
SegmentStateOffset()102 Offset JNIEnvExt::SegmentStateOffset() {
103   return Offset(OFFSETOF_MEMBER(JNIEnvExt, locals) +
104                 IndirectReferenceTable::SegmentStateOffset().Int32Value());
105 }
106 
107 }  // namespace art
108