Home | History | Annotate | Download | only in dex
      1 /*
      2  * Copyright (C) 2013 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 "verification_results.h"
     18 
     19 #include "base/logging.h"
     20 #include "base/mutex-inl.h"
     21 #include "base/stl_util.h"
     22 #include "driver/compiler_driver.h"
     23 #include "driver/compiler_options.h"
     24 #include "runtime.h"
     25 #include "thread.h"
     26 #include "thread-current-inl.h"
     27 #include "utils/atomic_dex_ref_map-inl.h"
     28 #include "verified_method.h"
     29 #include "verifier/method_verifier-inl.h"
     30 
     31 namespace art {
     32 
     33 VerificationResults::VerificationResults(const CompilerOptions* compiler_options)
     34     : compiler_options_(compiler_options),
     35       verified_methods_lock_("compiler verified methods lock"),
     36       rejected_classes_lock_("compiler rejected classes lock") {}
     37 
     38 VerificationResults::~VerificationResults() {
     39   WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
     40   STLDeleteValues(&verified_methods_);
     41   atomic_verified_methods_.Visit([](const DexFileReference& ref ATTRIBUTE_UNUSED,
     42                                     const VerifiedMethod* method) {
     43     delete method;
     44   });
     45 }
     46 
     47 void VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
     48   DCHECK(method_verifier != nullptr);
     49   if (!compiler_options_->IsAnyCompilationEnabled()) {
     50     // Verified methods are only required for quickening and compilation.
     51     return;
     52   }
     53   MethodReference ref = method_verifier->GetMethodReference();
     54   std::unique_ptr<const VerifiedMethod> verified_method(VerifiedMethod::Create(method_verifier));
     55   if (verified_method == nullptr) {
     56     // We'll punt this later.
     57     return;
     58   }
     59   AtomicMap::InsertResult result = atomic_verified_methods_.Insert(
     60       DexFileReference(ref.dex_file, ref.dex_method_index),
     61       /*expected*/ nullptr,
     62       verified_method.get());
     63   const VerifiedMethod* existing = nullptr;
     64   bool inserted;
     65   if (result != AtomicMap::kInsertResultInvalidDexFile) {
     66     inserted = (result == AtomicMap::kInsertResultSuccess);
     67     if (!inserted) {
     68       // Rare case.
     69       CHECK(atomic_verified_methods_.Get(DexFileReference(ref.dex_file, ref.dex_method_index),
     70                                          &existing));
     71       CHECK_NE(verified_method.get(), existing);
     72     }
     73   } else {
     74     WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
     75     auto it = verified_methods_.find(ref);
     76     inserted = it == verified_methods_.end();
     77     if (inserted) {
     78       verified_methods_.Put(ref, verified_method.get());
     79       DCHECK(verified_methods_.find(ref) != verified_methods_.end());
     80     } else {
     81       existing = it->second;
     82     }
     83   }
     84   if (inserted) {
     85     // Successfully added, release the unique_ptr since we no longer have ownership.
     86     DCHECK_EQ(GetVerifiedMethod(ref), verified_method.get());
     87     verified_method.release();
     88   } else {
     89     // TODO: Investigate why are we doing the work again for this method and try to avoid it.
     90     LOG(WARNING) << "Method processed more than once: " << ref.PrettyMethod();
     91     if (!Runtime::Current()->UseJitCompilation()) {
     92       if (kIsDebugBuild) {
     93         auto ex_set = existing->GetSafeCastSet();
     94         auto ve_set = verified_method->GetSafeCastSet();
     95         CHECK_EQ(ex_set == nullptr, ve_set == nullptr);
     96         CHECK((ex_set == nullptr) || (ex_set->size() == ve_set->size()));
     97       }
     98     }
     99     // Let the unique_ptr delete the new verified method since there was already an existing one
    100     // registered. It is unsafe to replace the existing one since the JIT may be using it to
    101     // generate a native GC map.
    102   }
    103 }
    104 
    105 const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) {
    106   const VerifiedMethod* ret = nullptr;
    107   DCHECK(compiler_options_->IsAnyCompilationEnabled());
    108   if (atomic_verified_methods_.Get(DexFileReference(ref.dex_file, ref.dex_method_index), &ret)) {
    109     return ret;
    110   }
    111   ReaderMutexLock mu(Thread::Current(), verified_methods_lock_);
    112   auto it = verified_methods_.find(ref);
    113   return (it != verified_methods_.end()) ? it->second : nullptr;
    114 }
    115 
    116 void VerificationResults::CreateVerifiedMethodFor(MethodReference ref) {
    117   // This method should only be called for classes verified at compile time,
    118   // which have no verifier error, nor has methods that we know will throw
    119   // at runtime.
    120   std::unique_ptr<VerifiedMethod> verified_method = std::make_unique<VerifiedMethod>(
    121       /* encountered_error_types */ 0, /* has_runtime_throw */ false);
    122   if (atomic_verified_methods_.Insert(DexFileReference(ref.dex_file, ref.dex_method_index),
    123                                       /*expected*/ nullptr,
    124                                       verified_method.get()) ==
    125           AtomicMap::InsertResult::kInsertResultSuccess) {
    126     verified_method.release();
    127   }
    128 }
    129 
    130 void VerificationResults::AddRejectedClass(ClassReference ref) {
    131   {
    132     WriterMutexLock mu(Thread::Current(), rejected_classes_lock_);
    133     rejected_classes_.insert(ref);
    134   }
    135   DCHECK(IsClassRejected(ref));
    136 }
    137 
    138 bool VerificationResults::IsClassRejected(ClassReference ref) {
    139   ReaderMutexLock mu(Thread::Current(), rejected_classes_lock_);
    140   return (rejected_classes_.find(ref) != rejected_classes_.end());
    141 }
    142 
    143 bool VerificationResults::IsCandidateForCompilation(MethodReference&,
    144                                                     const uint32_t access_flags) {
    145   if (!compiler_options_->IsAotCompilationEnabled()) {
    146     return false;
    147   }
    148   // Don't compile class initializers unless kEverything.
    149   if ((compiler_options_->GetCompilerFilter() != CompilerFilter::kEverything) &&
    150      ((access_flags & kAccConstructor) != 0) && ((access_flags & kAccStatic) != 0)) {
    151     return false;
    152   }
    153   return true;
    154 }
    155 
    156 void VerificationResults::AddDexFile(const DexFile* dex_file) {
    157   atomic_verified_methods_.AddDexFile(dex_file, dex_file->NumMethodIds());
    158   WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
    159   // There can be some verified methods that are already registered for the dex_file since we set
    160   // up well known classes earlier. Remove these and put them in the array so that we don't
    161   // accidentally miss seeing them.
    162   for (auto it = verified_methods_.begin(); it != verified_methods_.end(); ) {
    163     MethodReference ref = it->first;
    164     if (ref.dex_file == dex_file) {
    165       CHECK(atomic_verified_methods_.Insert(DexFileReference(ref.dex_file, ref.dex_method_index),
    166                                             nullptr,
    167                                             it->second) ==
    168           AtomicMap::kInsertResultSuccess);
    169       it = verified_methods_.erase(it);
    170     } else {
    171       ++it;
    172     }
    173   }
    174 }
    175 
    176 }  // namespace art
    177