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 "art_method-inl.h"
     20 #include "base/stringpiece.h"
     21 #include "class-inl.h"
     22 #include "dex_file-inl.h"
     23 #include "dex_instruction.h"
     24 #include "gc/accounting/card_table-inl.h"
     25 #include "interpreter/interpreter.h"
     26 #include "jni_internal.h"
     27 #include "mapping_table.h"
     28 #include "object-inl.h"
     29 #include "object_array.h"
     30 #include "object_array-inl.h"
     31 #include "string.h"
     32 #include "object_utils.h"
     33 
     34 namespace art {
     35 namespace mirror {
     36 
     37 extern "C" void art_portable_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, char);
     38 extern "C" void art_quick_invoke_stub(ArtMethod*, uint32_t*, uint32_t, Thread*, JValue*, char);
     39 
     40 // TODO: get global references for these
     41 Class* ArtMethod::java_lang_reflect_ArtMethod_ = NULL;
     42 
     43 InvokeType ArtMethod::GetInvokeType() const {
     44   // TODO: kSuper?
     45   if (GetDeclaringClass()->IsInterface()) {
     46     return kInterface;
     47   } else if (IsStatic()) {
     48     return kStatic;
     49   } else if (IsDirect()) {
     50     return kDirect;
     51   } else {
     52     return kVirtual;
     53   }
     54 }
     55 
     56 void ArtMethod::SetClass(Class* java_lang_reflect_ArtMethod) {
     57   CHECK(java_lang_reflect_ArtMethod_ == NULL);
     58   CHECK(java_lang_reflect_ArtMethod != NULL);
     59   java_lang_reflect_ArtMethod_ = java_lang_reflect_ArtMethod;
     60 }
     61 
     62 void ArtMethod::ResetClass() {
     63   CHECK(java_lang_reflect_ArtMethod_ != NULL);
     64   java_lang_reflect_ArtMethod_ = NULL;
     65 }
     66 
     67 void ArtMethod::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
     68   SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_),
     69                  new_dex_cache_strings, false);
     70 }
     71 
     72 void ArtMethod::SetDexCacheResolvedMethods(ObjectArray<ArtMethod>* new_dex_cache_methods) {
     73   SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_),
     74                  new_dex_cache_methods, false);
     75 }
     76 
     77 void ArtMethod::SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_classes) {
     78   SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_),
     79                  new_dex_cache_classes, false);
     80 }
     81 
     82 void ArtMethod::SetDexCacheInitializedStaticStorage(ObjectArray<StaticStorageBase>* new_value) {
     83   SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_initialized_static_storage_),
     84       new_value, false);
     85 }
     86 
     87 size_t ArtMethod::NumArgRegisters(const StringPiece& shorty) {
     88   CHECK_LE(1, shorty.length());
     89   uint32_t num_registers = 0;
     90   for (int i = 1; i < shorty.length(); ++i) {
     91     char ch = shorty[i];
     92     if (ch == 'D' || ch == 'J') {
     93       num_registers += 2;
     94     } else {
     95       num_registers += 1;
     96     }
     97   }
     98   return num_registers;
     99 }
    100 
    101 bool ArtMethod::IsProxyMethod() const {
    102   return GetDeclaringClass()->IsProxyClass();
    103 }
    104 
    105 ArtMethod* ArtMethod::FindOverriddenMethod() const {
    106   if (IsStatic()) {
    107     return NULL;
    108   }
    109   Class* declaring_class = GetDeclaringClass();
    110   Class* super_class = declaring_class->GetSuperClass();
    111   uint16_t method_index = GetMethodIndex();
    112   ObjectArray<ArtMethod>* super_class_vtable = super_class->GetVTable();
    113   ArtMethod* result = NULL;
    114   // Did this method override a super class method? If so load the result from the super class'
    115   // vtable
    116   if (super_class_vtable != NULL && method_index < super_class_vtable->GetLength()) {
    117     result = super_class_vtable->Get(method_index);
    118   } else {
    119     // Method didn't override superclass method so search interfaces
    120     if (IsProxyMethod()) {
    121       result = GetDexCacheResolvedMethods()->Get(GetDexMethodIndex());
    122       CHECK_EQ(result,
    123                Runtime::Current()->GetClassLinker()->FindMethodForProxy(GetDeclaringClass(), this));
    124     } else {
    125       MethodHelper mh(this);
    126       MethodHelper interface_mh;
    127       IfTable* iftable = GetDeclaringClass()->GetIfTable();
    128       for (size_t i = 0; i < iftable->Count() && result == NULL; i++) {
    129         Class* interface = iftable->GetInterface(i);
    130         for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
    131           ArtMethod* interface_method = interface->GetVirtualMethod(j);
    132           interface_mh.ChangeMethod(interface_method);
    133           if (mh.HasSameNameAndSignature(&interface_mh)) {
    134             result = interface_method;
    135             break;
    136           }
    137         }
    138       }
    139     }
    140   }
    141 #ifndef NDEBUG
    142   MethodHelper result_mh(result);
    143   DCHECK(result == NULL || MethodHelper(this).HasSameNameAndSignature(&result_mh));
    144 #endif
    145   return result;
    146 }
    147 
    148 uintptr_t ArtMethod::NativePcOffset(const uintptr_t pc) const {
    149   const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this);
    150   return pc - reinterpret_cast<uintptr_t>(code);
    151 }
    152 
    153 uint32_t ArtMethod::ToDexPc(const uintptr_t pc) const {
    154 #if !defined(ART_USE_PORTABLE_COMPILER)
    155   MappingTable table(GetMappingTable());
    156   if (table.TotalSize() == 0) {
    157     DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this);
    158     return DexFile::kDexNoIndex;   // Special no mapping case
    159   }
    160   const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this);
    161   uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(code);
    162   // Assume the caller wants a pc-to-dex mapping so check here first.
    163   typedef MappingTable::PcToDexIterator It;
    164   for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) {
    165     if (cur.NativePcOffset() == sought_offset) {
    166       return cur.DexPc();
    167     }
    168   }
    169   // Now check dex-to-pc mappings.
    170   typedef MappingTable::DexToPcIterator It2;
    171   for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
    172     if (cur.NativePcOffset() == sought_offset) {
    173       return cur.DexPc();
    174     }
    175   }
    176   LOG(FATAL) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset)
    177              << "(PC " << reinterpret_cast<void*>(pc) << ", code=" << code
    178              << ") in " << PrettyMethod(this);
    179   return DexFile::kDexNoIndex;
    180 #else
    181   // Compiler LLVM doesn't use the machine pc, we just use dex pc instead.
    182   return static_cast<uint32_t>(pc);
    183 #endif
    184 }
    185 
    186 uintptr_t ArtMethod::ToNativePc(const uint32_t dex_pc) const {
    187   MappingTable table(GetMappingTable());
    188   if (table.TotalSize() == 0) {
    189     DCHECK_EQ(dex_pc, 0U);
    190     return 0;   // Special no mapping/pc == 0 case
    191   }
    192   // Assume the caller wants a dex-to-pc mapping so check here first.
    193   typedef MappingTable::DexToPcIterator It;
    194   for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) {
    195     if (cur.DexPc() == dex_pc) {
    196       const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this);
    197       return reinterpret_cast<uintptr_t>(code) + 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       const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this);
    205       return reinterpret_cast<uintptr_t>(code) + cur.NativePcOffset();
    206     }
    207   }
    208   LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc
    209              << " in " << PrettyMethod(this);
    210   return 0;
    211 }
    212 
    213 uint32_t ArtMethod::FindCatchBlock(Class* exception_type, uint32_t dex_pc,
    214                                    bool* has_no_move_exception) const {
    215   MethodHelper mh(this);
    216   const DexFile::CodeItem* code_item = mh.GetCodeItem();
    217   // Default to handler not found.
    218   uint32_t found_dex_pc = DexFile::kDexNoIndex;
    219   // Iterate over the catch handlers associated with dex_pc.
    220   for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
    221     uint16_t iter_type_idx = it.GetHandlerTypeIndex();
    222     // Catch all case
    223     if (iter_type_idx == DexFile::kDexNoIndex16) {
    224       found_dex_pc = it.GetHandlerAddress();
    225       break;
    226     }
    227     // Does this catch exception type apply?
    228     Class* iter_exception_type = mh.GetDexCacheResolvedType(iter_type_idx);
    229     if (iter_exception_type == NULL) {
    230       // The verifier should take care of resolving all exception classes early
    231       LOG(WARNING) << "Unresolved exception class when finding catch block: "
    232         << mh.GetTypeDescriptorFromTypeIdx(iter_type_idx);
    233     } else if (iter_exception_type->IsAssignableFrom(exception_type)) {
    234       found_dex_pc = it.GetHandlerAddress();
    235       break;
    236     }
    237   }
    238   if (found_dex_pc != DexFile::kDexNoIndex) {
    239     const Instruction* first_catch_instr =
    240         Instruction::At(&mh.GetCodeItem()->insns_[found_dex_pc]);
    241     *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION);
    242   }
    243   return found_dex_pc;
    244 }
    245 
    246 void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result,
    247                        char result_type) {
    248   if (kIsDebugBuild) {
    249     self->AssertThreadSuspensionIsAllowable();
    250     CHECK_EQ(kRunnable, self->GetState());
    251   }
    252 
    253   // Push a transition back into managed code onto the linked list in thread.
    254   ManagedStack fragment;
    255   self->PushManagedStackFragment(&fragment);
    256 
    257   Runtime* runtime = Runtime::Current();
    258   // Call the invoke stub, passing everything as arguments.
    259   if (UNLIKELY(!runtime->IsStarted())) {
    260     LOG(INFO) << "Not invoking " << PrettyMethod(this) << " for a runtime that isn't started";
    261     if (result != NULL) {
    262       result->SetJ(0);
    263     }
    264   } else {
    265     const bool kLogInvocationStartAndReturn = false;
    266     if (GetEntryPointFromCompiledCode() != NULL) {
    267       if (kLogInvocationStartAndReturn) {
    268         LOG(INFO) << StringPrintf("Invoking '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
    269       }
    270 #ifdef ART_USE_PORTABLE_COMPILER
    271       (*art_portable_invoke_stub)(this, args, args_size, self, result, result_type);
    272 #else
    273       (*art_quick_invoke_stub)(this, args, args_size, self, result, result_type);
    274 #endif
    275       if (UNLIKELY(reinterpret_cast<int32_t>(self->GetException(NULL)) == -1)) {
    276         // Unusual case where we were running LLVM generated code and an
    277         // exception was thrown to force the activations to be removed from the
    278         // stack. Continue execution in the interpreter.
    279         self->ClearException();
    280         ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
    281         self->SetTopOfStack(NULL, 0);
    282         self->SetTopOfShadowStack(shadow_frame);
    283         interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
    284       }
    285       if (kLogInvocationStartAndReturn) {
    286         LOG(INFO) << StringPrintf("Returned '%s' code=%p", PrettyMethod(this).c_str(), GetEntryPointFromCompiledCode());
    287       }
    288     } else {
    289       LOG(INFO) << "Not invoking '" << PrettyMethod(this)
    290           << "' code=" << reinterpret_cast<const void*>(GetEntryPointFromCompiledCode());
    291       if (result != NULL) {
    292         result->SetJ(0);
    293       }
    294     }
    295   }
    296 
    297   // Pop transition.
    298   self->PopManagedStackFragment(fragment);
    299 }
    300 
    301 bool ArtMethod::IsRegistered() const {
    302   void* native_method = GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, native_method_), false);
    303   CHECK(native_method != NULL);
    304   void* jni_stub = GetJniDlsymLookupStub();
    305   return native_method != jni_stub;
    306 }
    307 
    308 extern "C" void art_work_around_app_jni_bugs(JNIEnv*, jobject);
    309 void ArtMethod::RegisterNative(Thread* self, const void* native_method) {
    310   DCHECK(Thread::Current() == self);
    311   CHECK(IsNative()) << PrettyMethod(this);
    312   CHECK(native_method != NULL) << PrettyMethod(this);
    313   if (!self->GetJniEnv()->vm->work_around_app_jni_bugs) {
    314     SetNativeMethod(native_method);
    315   } else {
    316     // We've been asked to associate this method with the given native method but are working
    317     // around JNI bugs, that include not giving Object** SIRT references to native methods. Direct
    318     // the native method to runtime support and store the target somewhere runtime support will
    319     // find it.
    320 #if defined(__i386__)
    321     UNIMPLEMENTED(FATAL);
    322 #else
    323     SetNativeMethod(reinterpret_cast<void*>(art_work_around_app_jni_bugs));
    324 #endif
    325     SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_),
    326         reinterpret_cast<const uint8_t*>(native_method), false);
    327   }
    328 }
    329 
    330 void ArtMethod::UnregisterNative(Thread* self) {
    331   CHECK(IsNative()) << PrettyMethod(this);
    332   // restore stub to lookup native pointer via dlsym
    333   RegisterNative(self, GetJniDlsymLookupStub());
    334 }
    335 
    336 void ArtMethod::SetNativeMethod(const void* native_method) {
    337   SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, native_method_),
    338       native_method, false);
    339 }
    340 
    341 }  // namespace mirror
    342 }  // namespace art
    343