1 /*
2  * Copyright (C) 2014 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 #ifndef ART_RUNTIME_INDIRECT_REFERENCE_TABLE_INL_H_
18 #define ART_RUNTIME_INDIRECT_REFERENCE_TABLE_INL_H_
19 
20 #include "indirect_reference_table.h"
21 
22 #include "verify_object-inl.h"
23 
24 namespace art {
25 namespace mirror {
26 class Object;
27 }  // namespace mirror
28 
29 // Verifies that the indirect table lookup is valid.
30 // Returns "false" if something looks bad.
GetChecked(IndirectRef iref)31 inline bool IndirectReferenceTable::GetChecked(IndirectRef iref) const {
32   if (UNLIKELY(iref == nullptr)) {
33     LOG(WARNING) << "Attempt to look up NULL " << kind_;
34     return false;
35   }
36   if (UNLIKELY(GetIndirectRefKind(iref) == kHandleScopeOrInvalid)) {
37     LOG(ERROR) << "JNI ERROR (app bug): invalid " << kind_ << " " << iref;
38     AbortIfNoCheckJNI();
39     return false;
40   }
41   const int topIndex = segment_state_.parts.topIndex;
42   int idx = ExtractIndex(iref);
43   if (UNLIKELY(idx >= topIndex)) {
44     LOG(ERROR) << "JNI ERROR (app bug): accessed stale " << kind_ << " "
45                << iref << " (index " << idx << " in a table of size " << topIndex << ")";
46     AbortIfNoCheckJNI();
47     return false;
48   }
49   if (UNLIKELY(table_[idx].GetReference()->IsNull())) {
50     LOG(ERROR) << "JNI ERROR (app bug): accessed deleted " << kind_ << " " << iref;
51     AbortIfNoCheckJNI();
52     return false;
53   }
54   if (UNLIKELY(!CheckEntry("use", iref, idx))) {
55     return false;
56   }
57   return true;
58 }
59 
60 // Make sure that the entry at "idx" is correctly paired with "iref".
CheckEntry(const char * what,IndirectRef iref,int idx)61 inline bool IndirectReferenceTable::CheckEntry(const char* what, IndirectRef iref, int idx) const {
62   IndirectRef checkRef = ToIndirectRef(idx);
63   if (UNLIKELY(checkRef != iref)) {
64     LOG(ERROR) << "JNI ERROR (app bug): attempt to " << what
65                << " stale " << kind_ << " " << iref
66                << " (should be " << checkRef << ")";
67     AbortIfNoCheckJNI();
68     return false;
69   }
70   return true;
71 }
72 
73 template<ReadBarrierOption kReadBarrierOption>
Get(IndirectRef iref)74 inline mirror::Object* IndirectReferenceTable::Get(IndirectRef iref) const {
75   if (!GetChecked(iref)) {
76     return kInvalidIndirectRefObject;
77   }
78   uint32_t idx = ExtractIndex(iref);
79   mirror::Object* obj = table_[idx].GetReference()->Read<kWithoutReadBarrier>();
80   if (LIKELY(obj != kClearedJniWeakGlobal)) {
81     // The read barrier or VerifyObject won't handle kClearedJniWeakGlobal.
82     obj = table_[idx].GetReference()->Read();
83     VerifyObject(obj);
84   }
85   return obj;
86 }
87 
88 }  // namespace art
89 
90 #endif  // ART_RUNTIME_INDIRECT_REFERENCE_TABLE_INL_H_
91