| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 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 | #include "verified_method.h" | 
 | 18 |  | 
 | 19 | #include <algorithm> | 
| Ian Rogers | 700a402 | 2014-05-19 16:49:03 -0700 | [diff] [blame] | 20 | #include <memory> | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 21 |  | 
| Andreas Gampe | 5794381 | 2017-12-06 21:39:13 -0800 | [diff] [blame] | 22 | #include <android-base/logging.h> | 
 | 23 |  | 
| David Sehr | 9e734c7 | 2018-01-04 17:56:19 -0800 | [diff] [blame] | 24 | #include "dex/code_item_accessors-inl.h" | 
 | 25 | #include "dex/dex_file.h" | 
 | 26 | #include "dex/dex_instruction-inl.h" | 
| Andreas Gampe | c6ea7d0 | 2017-02-01 16:46:28 -0800 | [diff] [blame] | 27 | #include "runtime.h" | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 28 | #include "verifier/method_verifier-inl.h" | 
| Ian Rogers | 7b078e8 | 2014-09-10 14:44:24 -0700 | [diff] [blame] | 29 | #include "verifier/reg_type-inl.h" | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 30 | #include "verifier/register_line-inl.h" | 
| Andreas Gampe | c6ea7d0 | 2017-02-01 16:46:28 -0800 | [diff] [blame] | 31 | #include "verifier/verifier_deps.h" | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 32 |  | 
 | 33 | namespace art { | 
 | 34 |  | 
| Nicolas Geoffray | 98e6ce4 | 2016-02-16 18:42:15 +0000 | [diff] [blame] | 35 | VerifiedMethod::VerifiedMethod(uint32_t encountered_error_types, bool has_runtime_throw) | 
| Andreas Gampe | 0760a81 | 2015-08-26 17:12:51 -0700 | [diff] [blame] | 36 |     : encountered_error_types_(encountered_error_types), | 
| Nicolas Geoffray | 98e6ce4 | 2016-02-16 18:42:15 +0000 | [diff] [blame] | 37 |       has_runtime_throw_(has_runtime_throw) { | 
| Andreas Gampe | 0760a81 | 2015-08-26 17:12:51 -0700 | [diff] [blame] | 38 | } | 
 | 39 |  | 
| Nicolas Geoffray | c51c7ca | 2016-11-25 15:46:48 +0000 | [diff] [blame] | 40 | const VerifiedMethod* VerifiedMethod::Create(verifier::MethodVerifier* method_verifier) { | 
 | 41 |   DCHECK(Runtime::Current()->IsAotCompiler()); | 
| Andreas Gampe | 0760a81 | 2015-08-26 17:12:51 -0700 | [diff] [blame] | 42 |   std::unique_ptr<VerifiedMethod> verified_method( | 
 | 43 |       new VerifiedMethod(method_verifier->GetEncounteredFailureTypes(), | 
| Nicolas Geoffray | 98e6ce4 | 2016-02-16 18:42:15 +0000 | [diff] [blame] | 44 |                          method_verifier->HasInstructionThatWillThrow())); | 
| Andreas Gampe | 0760a81 | 2015-08-26 17:12:51 -0700 | [diff] [blame] | 45 |  | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 46 |   if (method_verifier->HasCheckCasts()) { | 
 | 47 |     verified_method->GenerateSafeCastSet(method_verifier); | 
 | 48 |   } | 
| Jeff Hao | 848f70a | 2014-01-15 13:49:50 -0800 | [diff] [blame] | 49 |  | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 50 |   return verified_method.release(); | 
 | 51 | } | 
 | 52 |  | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 53 | bool VerifiedMethod::IsSafeCast(uint32_t pc) const { | 
| Andreas Gampe | 26699c6 | 2017-05-12 08:19:28 -0700 | [diff] [blame] | 54 |   if (safe_cast_set_ == nullptr) { | 
 | 55 |     return false; | 
 | 56 |   } | 
 | 57 |   return std::binary_search(safe_cast_set_->begin(), safe_cast_set_->end(), pc); | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 58 | } | 
 | 59 |  | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 60 | void VerifiedMethod::GenerateSafeCastSet(verifier::MethodVerifier* method_verifier) { | 
 | 61 |   /* | 
 | 62 |    * Walks over the method code and adds any cast instructions in which | 
 | 63 |    * the type cast is implicit to a set, which is used in the code generation | 
 | 64 |    * to elide these casts. | 
 | 65 |    */ | 
 | 66 |   if (method_verifier->HasFailures()) { | 
 | 67 |     return; | 
 | 68 |   } | 
| Mathieu Chartier | 3da1d0f | 2017-11-06 20:02:24 -0800 | [diff] [blame] | 69 |   for (const DexInstructionPcPair& pair : method_verifier->CodeItem()) { | 
| Mathieu Chartier | 2b2bef2 | 2017-10-26 17:10:19 -0700 | [diff] [blame] | 70 |     const Instruction& inst = pair.Inst(); | 
| Mathieu Chartier | 1d2d4ff | 2017-09-23 16:11:06 -0700 | [diff] [blame] | 71 |     const Instruction::Code code = inst.Opcode(); | 
| Nicolas Geoffray | d1665a0 | 2016-12-12 13:07:07 +0000 | [diff] [blame] | 72 |     if (code == Instruction::CHECK_CAST) { | 
| Mathieu Chartier | 2b2bef2 | 2017-10-26 17:10:19 -0700 | [diff] [blame] | 73 |       const uint32_t dex_pc = pair.DexPc(); | 
| Stephen Kyle | 40d3518 | 2014-10-03 13:47:56 +0100 | [diff] [blame] | 74 |       if (!method_verifier->GetInstructionFlags(dex_pc).IsVisited()) { | 
 | 75 |         // Do not attempt to quicken this instruction, it's unreachable anyway. | 
 | 76 |         continue; | 
 | 77 |       } | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 78 |       const verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc); | 
| Andreas Gampe | 93adcb5 | 2019-06-06 20:16:07 -0700 | [diff] [blame] | 79 |       DCHECK(line != nullptr) << "Did not have line for dex pc 0x" << std::hex << dex_pc; | 
| Nicolas Geoffray | d1665a0 | 2016-12-12 13:07:07 +0000 | [diff] [blame] | 80 |       const verifier::RegType& reg_type(line->GetRegisterType(method_verifier, | 
| Mathieu Chartier | 1d2d4ff | 2017-09-23 16:11:06 -0700 | [diff] [blame] | 81 |                                                               inst.VRegA_21c())); | 
| Nicolas Geoffray | d1665a0 | 2016-12-12 13:07:07 +0000 | [diff] [blame] | 82 |       const verifier::RegType& cast_type = | 
| Mathieu Chartier | 1d2d4ff | 2017-09-23 16:11:06 -0700 | [diff] [blame] | 83 |           method_verifier->ResolveCheckedClass(dex::TypeIndex(inst.VRegB_21c())); | 
| Nicolas Geoffray | 119e846 | 2016-12-21 10:29:43 +0000 | [diff] [blame] | 84 |       // Pass null for the method verifier to not record the VerifierDeps dependency | 
 | 85 |       // if the types are not assignable. | 
| Andreas Gampe | 3db7068 | 2018-12-26 15:12:03 -0800 | [diff] [blame] | 86 |       if (cast_type.IsStrictlyAssignableFrom(reg_type, /* verifier= */ nullptr)) { | 
| Nicolas Geoffray | 119e846 | 2016-12-21 10:29:43 +0000 | [diff] [blame] | 87 |         // The types are assignable, we record that dependency in the VerifierDeps so | 
 | 88 |         // that if this changes after OTA, we will re-verify again. | 
 | 89 |         // We check if reg_type has a class, as the verifier may have inferred it's | 
 | 90 |         // 'null'. | 
 | 91 |         if (reg_type.HasClass()) { | 
 | 92 |           DCHECK(cast_type.HasClass()); | 
 | 93 |           verifier::VerifierDeps::MaybeRecordAssignability(method_verifier->GetDexFile(), | 
 | 94 |                                                            cast_type.GetClass(), | 
 | 95 |                                                            reg_type.GetClass(), | 
| Andreas Gampe | 3db7068 | 2018-12-26 15:12:03 -0800 | [diff] [blame] | 96 |                                                            /* is_strict= */ true, | 
 | 97 |                                                            /* is_assignable= */ true); | 
| Nicolas Geoffray | 119e846 | 2016-12-21 10:29:43 +0000 | [diff] [blame] | 98 |         } | 
| Andreas Gampe | 26699c6 | 2017-05-12 08:19:28 -0700 | [diff] [blame] | 99 |         if (safe_cast_set_ == nullptr) { | 
 | 100 |           safe_cast_set_.reset(new SafeCastSet()); | 
 | 101 |         } | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 102 |         // Verify ordering for push_back() to the sorted vector. | 
| Andreas Gampe | 26699c6 | 2017-05-12 08:19:28 -0700 | [diff] [blame] | 103 |         DCHECK(safe_cast_set_->empty() || safe_cast_set_->back() < dex_pc); | 
 | 104 |         safe_cast_set_->push_back(dex_pc); | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 105 |       } | 
 | 106 |     } | 
 | 107 |   } | 
| Andreas Gampe | 26699c6 | 2017-05-12 08:19:28 -0700 | [diff] [blame] | 108 |   DCHECK(safe_cast_set_ == nullptr || !safe_cast_set_->empty()); | 
| Vladimir Marko | c7f8320 | 2014-01-24 17:55:18 +0000 | [diff] [blame] | 109 | } | 
 | 110 |  | 
 | 111 | }  // namespace art |