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 "art_method.h"
18 
19 #include "arch/context.h"
20 #include "art_field-inl.h"
21 #include "art_method-inl.h"
22 #include "base/stringpiece.h"
23 #include "class-inl.h"
24 #include "dex_file-inl.h"
25 #include "dex_instruction.h"
26 #include "gc/accounting/card_table-inl.h"
27 #include "interpreter/interpreter.h"
28 #include "jni_internal.h"
29 #include "mapping_table.h"
30 #include "method_helper-inl.h"
31 #include "object_array-inl.h"
32 #include "object_array.h"
33 #include "object-inl.h"
34 #include "scoped_thread_state_change.h"
35 #include "string.h"
36 #include "well_known_classes.h"
37 
38 namespace art {
39 namespace mirror {
40 
41 extern "C" void art_portable_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, char);
42 extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
43                                       const char*);
44 #ifdef __LP64__
45 extern "C" void art_quick_invoke_static_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*,
46                                              const char*);
47 #endif
48 
49 // TODO: get global references for these
50 GcRoot<Class> ArtMethod::java_lang_reflect_ArtMethod_;
51 
FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable & soa,jobject jlr_method)52 ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
53                                           jobject jlr_method) {
54   mirror::ArtField* f =
55       soa.DecodeField(WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
56   mirror::ArtMethod* method = f->GetObject(soa.Decode<mirror::Object*>(jlr_method))->AsArtMethod();
57   DCHECK(method != nullptr);
58   return method;
59 }
60 
61 
VisitRoots(RootCallback * callback,void * arg)62 void ArtMethod::VisitRoots(RootCallback* callback, void* arg) {
63   java_lang_reflect_ArtMethod_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
64 }
65 
GetInvokeType()66 InvokeType ArtMethod::GetInvokeType() {
67   // TODO: kSuper?
68   if (GetDeclaringClass()->IsInterface()) {
69     return kInterface;
70   } else if (IsStatic()) {
71     return kStatic;
72   } else if (IsDirect()) {
73     return kDirect;
74   } else {
75     return kVirtual;
76   }
77 }
78 
SetClass(Class * java_lang_reflect_ArtMethod)79 void ArtMethod::SetClass(Class* java_lang_reflect_ArtMethod) {
80   CHECK(java_lang_reflect_ArtMethod_.IsNull());
81   CHECK(java_lang_reflect_ArtMethod != NULL);
82   java_lang_reflect_ArtMethod_ = GcRoot<Class>(java_lang_reflect_ArtMethod);
83 }
84 
ResetClass()85 void ArtMethod::ResetClass() {
86   CHECK(!java_lang_reflect_ArtMethod_.IsNull());
87   java_lang_reflect_ArtMethod_ = GcRoot<Class>(nullptr);
88 }
89 
NumArgRegisters(const StringPiece & shorty)90 size_t ArtMethod::NumArgRegisters(const StringPiece& shorty) {
91   CHECK_LE(1, shorty.length());
92   uint32_t num_registers = 0;
93   for (int i = 1; i < shorty.length(); ++i) {
94     char ch = shorty[i];
95     if (ch == 'D' || ch == 'J') {
96       num_registers += 2;
97     } else {
98       num_registers += 1;
99     }
100   }
101   return num_registers;
102 }
103 
FindOverriddenMethod()104 ArtMethod* ArtMethod::FindOverriddenMethod() {
105   if (IsStatic()) {
106     return NULL;
107   }
108   Class* declaring_class = GetDeclaringClass();
109   Class* super_class = declaring_class->GetSuperClass();
110   uint16_t method_index = GetMethodIndex();
111   ArtMethod* result = NULL;
112   // Did this method override a super class method? If so load the result from the super class'
113   // vtable
114   if (super_class->HasVTable() && method_index < super_class->GetVTableLength()) {
115     result = super_class->GetVTableEntry(method_index);
116   } else {
117     // Method didn't override superclass method so search interfaces
118     if (IsProxyMethod()) {
119       result = GetDexCacheResolvedMethods()->Get(GetDexMethodIndex());
120       CHECK_EQ(result,
121                Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this));
122     } else {
123       StackHandleScope<2> hs(Thread::Current());
124       MethodHelper mh(hs.NewHandle(this));
125       MethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
126       IfTable* iftable = GetDeclaringClass()->GetIfTable();
127       for (size_t i = 0; i < iftable->Count() && result == NULL; i++) {
128         Class* interface = iftable->GetInterface(i);
129         for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
130           interface_mh.ChangeMethod(interface->GetVirtualMethod(j));
131           if (mh.HasSameNameAndSignature(&interface_mh)) {
132             result = interface_mh.GetMethod();
133             break;
134           }
135         }
136       }
137     }
138   }
139   if (kIsDebugBuild) {
140     StackHandleScope<2> hs(Thread::Current());
141     MethodHelper result_mh(hs.NewHandle(result));
142     MethodHelper this_mh(hs.NewHandle(this));
143     DCHECK(result == nullptr || this_mh.HasSameNameAndSignature(&result_mh));
144   }
145   return result;
146 }
147 
ToDexPc(const uintptr_t pc,bool abort_on_failure)148 uint32_t ArtMethod::ToDexPc(const uintptr_t pc, bool abort_on_failure) {
149   if (IsPortableCompiled()) {
150     // Portable doesn't use the machine pc, we just use dex pc instead.
151     return static_cast<uint32_t>(pc);
152   }
153   const void* entry_point = GetQuickOatEntryPoint(sizeof(void*));
154   MappingTable table(entry_point != nullptr ?
155       GetMappingTable(EntryPointToCodePointer(entry_point), sizeof(void*)) : nullptr);
156   if (table.TotalSize() == 0) {
157     // NOTE: Special methods (see Mir2Lir::GenSpecialCase()) have an empty mapping
158     // but they have no suspend checks and, consequently, we never call ToDexPc() for them.
159     DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
160     return DexFile::kDexNoIndex;   // Special no mapping case
161   }
162   uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(entry_point);
163   // Assume the caller wants a pc-to-dex mapping so check here first.
164   typedef MappingTable::PcToDexIterator It;
165   for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
166     if (cur.NativePcOffset() == sought_offset) {
167       return cur.DexPc();
168     }
169   }
170   // Now check dex-to-pc mappings.
171   typedef MappingTable::DexToPcIterator It2;
172   for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
173     if (cur.NativePcOffset() == sought_offset) {
174       return cur.DexPc();
175     }
176   }
177   if (abort_on_failure) {
178       LOG(FATAL) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset)
179              << "(PC " << reinterpret_cast<void*>(pc) << ", entry_point=" << entry_point
180              << ") in " << PrettyMethod(this);
181   }
182   return DexFile::kDexNoIndex;
183 }
184 
ToNativePc(const uint32_t dex_pc)185 uintptr_t ArtMethod::ToNativePc(const uint32_t dex_pc) {
186   const void* entry_point = GetQuickOatEntryPoint(sizeof(void*));
187   MappingTable table(entry_point != nullptr ?
188       GetMappingTable(EntryPointToCodePointer(entry_point), sizeof(void*)) : nullptr);
189   if (table.TotalSize() == 0) {
190     DCHECK_EQ(dex_pc, 0U);
191     return 0;   // Special no mapping/pc == 0 case
192   }
193   // Assume the caller wants a dex-to-pc mapping so check here first.
194   typedef MappingTable::DexToPcIterator It;
195   for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
196     if (cur.DexPc() == dex_pc) {
197       return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
198     }
199   }
200   // Now check pc-to-dex mappings.
201   typedef MappingTable::PcToDexIterator It2;
202   for (It2 cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
203     if (cur.DexPc() == dex_pc) {
204       return reinterpret_cast<uintptr_t>(entry_point) + cur.NativePcOffset();
205     }
206   }
207   LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
208              << " in " << PrettyMethod(this);
209   return 0;
210 }
211 
FindCatchBlock(Handle<ArtMethod> h_this,Handle<Class> exception_type,uint32_t dex_pc,bool * has_no_move_exception)212 uint32_t ArtMethod::FindCatchBlock(Handle<ArtMethod> h_this, Handle<Class> exception_type,
213                                    uint32_t dex_pc, bool* has_no_move_exception) {
214   MethodHelper mh(h_this);
215   const DexFile::CodeItem* code_item = h_this->GetCodeItem();
216   // Set aside the exception while we resolve its type.
217   Thread* self = Thread::Current();
218   ThrowLocation throw_location;
219   StackHandleScope<1> hs(self);
220   Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException(&throw_location)));
221   bool is_exception_reported = self->IsExceptionReportedToInstrumentation();
222   self->ClearException();
223   // Default to handler not found.
224   uint32_t found_dex_pc = DexFile::kDexNoIndex;
225   // Iterate over the catch handlers associated with dex_pc.
226   for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
227     uint16_t iter_type_idx = it.GetHandlerTypeIndex();
228     // Catch all case
229     if (iter_type_idx == DexFile::kDexNoIndex16) {
230       found_dex_pc = it.GetHandlerAddress();
231       break;
232     }
233     // Does this catch exception type apply?
234     Class* iter_exception_type = mh.GetClassFromTypeIdx(iter_type_idx);
235     if (UNLIKELY(iter_exception_type == nullptr)) {
236       // Now have a NoClassDefFoundError as exception. Ignore in case the exception class was
237       // removed by a pro-guard like tool.
238       // Note: this is not RI behavior. RI would have failed when loading the class.
239       self->ClearException();
240       // Delete any long jump context as this routine is called during a stack walk which will
241       // release its in use context at the end.
242       delete self->GetLongJumpContext();
243       LOG(WARNING) << "Unresolved exception class when finding catch block: "
244         << DescriptorToDot(h_this->GetTypeDescriptorFromTypeIdx(iter_type_idx));
245     } else if (iter_exception_type->IsAssignableFrom(exception_type.Get())) {
246       found_dex_pc = it.GetHandlerAddress();
247       break;
248     }
249   }
250   if (found_dex_pc != DexFile::kDexNoIndex) {
251     const Instruction* first_catch_instr =
252         Instruction::At(&code_item->insns_[found_dex_pc]);
253     *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION);
254   }
255   // Put the exception back.
256   if (exception.Get() != nullptr) {
257     self->SetException(throw_location, exception.Get());
258     self->SetExceptionReportedToInstrumentation(is_exception_reported);
259   }
260   return found_dex_pc;
261 }
262 
Invoke(Thread * self,uint32_t * args,uint32_t args_size,JValue * result,const char * shorty)263 void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
264                        const char* shorty) {
265   if (UNLIKELY(__builtin_frame_address(0) < self->GetStackEnd())) {
266     ThrowStackOverflowError(self);
267     return;
268   }
269 
270   if (kIsDebugBuild) {
271     self->AssertThreadSuspensionIsAllowable();
272     CHECK_EQ(kRunnable, self->GetState());
273     CHECK_STREQ(GetShorty(), shorty);
274   }
275 
276   // Push a transition back into managed code onto the linked list in thread.
277   ManagedStack fragment;
278   self->PushManagedStackFragment(&fragment);
279 
280   Runtime* runtime = Runtime::Current();
281   // Call the invoke stub, passing everything as arguments.
282   if (UNLIKELY(!runtime->IsStarted())) {
283     if (IsStatic()) {
284       art::interpreter::EnterInterpreterFromInvoke(self, this, nullptr, args, result);
285     } else {
286       Object* receiver = reinterpret_cast<StackReference<Object>*>(&args[0])->AsMirrorPtr();
287       art::interpreter::EnterInterpreterFromInvoke(self, this, receiver, args + 1, result);
288     }
289   } else {
290     const bool kLogInvocationStartAndReturn = false;
291     bool have_quick_code = GetEntryPointFromQuickCompiledCode() != nullptr;
292 #if defined(ART_USE_PORTABLE_COMPILER)
293     bool have_portable_code = GetEntryPointFromPortableCompiledCode() != nullptr;
294 #else
295     bool have_portable_code = false;
296 #endif
297     if (LIKELY(have_quick_code || have_portable_code)) {
298       if (kLogInvocationStartAndReturn) {
299         LOG(INFO) << StringPrintf("Invoking '%s' %s code=%p", PrettyMethod(this).c_str(),
300                                   have_quick_code ? "quick" : "portable",
301                                   have_quick_code ? GetEntryPointFromQuickCompiledCode()
302 #if defined(ART_USE_PORTABLE_COMPILER)
303                                                   : GetEntryPointFromPortableCompiledCode());
304 #else
305                                                   : nullptr);
306 #endif
307       }
308       if (!IsPortableCompiled()) {
309 #ifdef __LP64__
310         if (!IsStatic()) {
311           (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
312         } else {
313           (*art_quick_invoke_static_stub)(this, args, args_size, self, result, shorty);
314         }
315 #else
316         (*art_quick_invoke_stub)(this, args, args_size, self, result, shorty);
317 #endif
318       } else {
319         (*art_portable_invoke_stub)(this, args, args_size, self, result, shorty[0]);
320       }
321       if (UNLIKELY(self->GetException(nullptr) == Thread::GetDeoptimizationException())) {
322         // Unusual case where we were running generated code and an
323         // exception was thrown to force the activations to be removed from the
324         // stack. Continue execution in the interpreter.
325         self->ClearException();
326         ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
327         self->SetTopOfStack(nullptr, 0);
328         self->SetTopOfShadowStack(shadow_frame);
329         interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
330       }
331       if (kLogInvocationStartAndReturn) {
332         LOG(INFO) << StringPrintf("Returned '%s' %s code=%p", PrettyMethod(this).c_str(),
333                                   have_quick_code ? "quick" : "portable",
334                                   have_quick_code ? GetEntryPointFromQuickCompiledCode()
335 #if defined(ART_USE_PORTABLE_COMPILER)
336                                                   : GetEntryPointFromPortableCompiledCode());
337 #else
338                                                   : nullptr);
339 #endif
340       }
341     } else {
342       LOG(INFO) << "Not invoking '" << PrettyMethod(this) << "' code=null";
343       if (result != NULL) {
344         result->SetJ(0);
345       }
346     }
347   }
348 
349   // Pop transition.
350   self->PopManagedStackFragment(fragment);
351 }
352 
RegisterNative(Thread * self,const void * native_method,bool is_fast)353 void ArtMethod::RegisterNative(Thread* self, const void* native_method, bool is_fast) {
354   DCHECK(Thread::Current() == self);
355   CHECK(IsNative()) << PrettyMethod(this);
356   CHECK(!IsFastNative()) << PrettyMethod(this);
357   CHECK(native_method != NULL) << PrettyMethod(this);
358   if (is_fast) {
359     SetAccessFlags(GetAccessFlags() | kAccFastNative);
360   }
361   SetEntryPointFromJni(native_method);
362 }
363 
UnregisterNative(Thread * self)364 void ArtMethod::UnregisterNative(Thread* self) {
365   CHECK(IsNative() && !IsFastNative()) << PrettyMethod(this);
366   // restore stub to lookup native pointer via dlsym
367   RegisterNative(self, GetJniDlsymLookupStub(), false);
368 }
369 
370 }  // namespace mirror
371 }  // namespace art
372