Home | History | Annotate | Download | only in mirror
      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 
     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 
     62 void ArtMethod::VisitRoots(RootCallback* callback, void* arg) {
     63   java_lang_reflect_ArtMethod_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass));
     64 }
     65 
     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 
     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 
     85 void ArtMethod::ResetClass() {
     86   CHECK(!java_lang_reflect_ArtMethod_.IsNull());
     87   java_lang_reflect_ArtMethod_ = GcRoot<Class>(nullptr);
     88 }
     89 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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