inline_method_analyser.cc revision 141de8c4cf18923b4ee773a455102734ca9e4407
1e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko/* 2e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * Copyright (C) 2014 The Android Open Source Project 3e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * 4e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * Licensed under the Apache License, Version 2.0 (the "License"); 5e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * you may not use this file except in compliance with the License. 6e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * You may obtain a copy of the License at 7e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * 8e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * http://www.apache.org/licenses/LICENSE-2.0 9e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * 10e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * Unless required by applicable law or agreed to in writing, software 11e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * distributed under the License is distributed on an "AS IS" BASIS, 12e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * See the License for the specific language governing permissions and 14e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * limitations under the License. 15e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko */ 16e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 17e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "inline_method_analyser.h" 18c785344b87221f5e4e6473e5b762e4e61fe65dcfMathieu Chartier 19c785344b87221f5e4e6473e5b762e4e61fe65dcfMathieu Chartier#include "art_field-inl.h" 20e401d146407d61eeb99f8d6176b2ac13c4df1e33Mathieu Chartier#include "art_method-inl.h" 213481ba2c4e4f3aa80d8c6d50a9f85dacb56b508bVladimir Marko#include "class_linker-inl.h" 22956af0f0cb05422e38c1d22cbef309d16b8a1a12Elliott Hughes#include "dex_file-inl.h" 23e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "dex_instruction.h" 24e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "dex_instruction-inl.h" 25354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko#include "dex_instruction_utils.h" 26e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/class-inl.h" 27e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/dex_cache-inl.h" 28e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "verifier/method_verifier-inl.h" 29e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 30e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko/* 31e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * NOTE: This code is part of the quick compiler. It lives in the runtime 32e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * only to allow the debugger to check whether a method has been inlined. 33e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko */ 34e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 35e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markonamespace art { 36e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 37354efa6cdf558b2331e8fec539893fa51763806eVladimir Markonamespace { // anonymous namespace 38354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 39354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// Helper class for matching a pattern. 40354efa6cdf558b2331e8fec539893fa51763806eVladimir Markoclass Matcher { 41354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko public: 42354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Match function type. 43354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko typedef bool MatchFn(Matcher* matcher); 44354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 45354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko template <size_t size> 46354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko static bool Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]); 47354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 48354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Match and advance. 49354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 50354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko static bool Mark(Matcher* matcher); 51354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 52354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko template <bool (Matcher::*Fn)()> 53354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko static bool Required(Matcher* matcher); 54354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 55354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko template <bool (Matcher::*Fn)()> 56354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko static bool Repeated(Matcher* matcher); // On match, returns to the mark. 57354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 58354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Match an individual instruction. 59354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 60354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko template <Instruction::Code opcode> bool Opcode(); 61354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko bool Const0(); 62354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko bool IPutOnThis(); 63354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 64354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko private: 65354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko explicit Matcher(const DexFile::CodeItem* code_item) 66354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko : code_item_(code_item), 67354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko instruction_(Instruction::At(code_item->insns_)), 68354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko pos_(0u), 69354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko mark_(0u) { } 70354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 71354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size); 72354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 73354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko const DexFile::CodeItem* const code_item_; 74354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko const Instruction* instruction_; 75354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko size_t pos_; 76354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko size_t mark_; 77354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko}; 78354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 79354efa6cdf558b2331e8fec539893fa51763806eVladimir Markotemplate <size_t size> 80354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool Matcher::Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]) { 81354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return DoMatch(code_item, pattern, size); 82354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 83354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 84354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool Matcher::Mark(Matcher* matcher) { 85354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko matcher->pos_ += 1u; // Advance to the next match function before marking. 86354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko matcher->mark_ = matcher->pos_; 87354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 88354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 89354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 90354efa6cdf558b2331e8fec539893fa51763806eVladimir Markotemplate <bool (Matcher::*Fn)()> 91354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool Matcher::Required(Matcher* matcher) { 92354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (!(matcher->*Fn)()) { 93354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 94354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 95354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko matcher->pos_ += 1u; 96354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko matcher->instruction_ = matcher->instruction_->Next(); 97354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 98354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 99354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 100354efa6cdf558b2331e8fec539893fa51763806eVladimir Markotemplate <bool (Matcher::*Fn)()> 101354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool Matcher::Repeated(Matcher* matcher) { 102354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (!(matcher->*Fn)()) { 103354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Didn't match optional instruction, try the next match function. 104354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko matcher->pos_ += 1u; 105354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 106354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 107354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko matcher->pos_ = matcher->mark_; 108354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko matcher->instruction_ = matcher->instruction_->Next(); 109354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 110354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 111354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 112354efa6cdf558b2331e8fec539893fa51763806eVladimir Markotemplate <Instruction::Code opcode> 113354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool Matcher::Opcode() { 114354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return instruction_->Opcode() == opcode; 115354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 116354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 117354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// Match const 0. 118354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool Matcher::Const0() { 119354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return IsInstructionDirectConst(instruction_->Opcode()) && 120354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko (instruction_->Opcode() == Instruction::CONST_WIDE ? instruction_->VRegB_51l() == 0 121354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko : instruction_->VRegB() == 0); 122354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 123354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 124354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool Matcher::IPutOnThis() { 125354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK_NE(code_item_->ins_size_, 0u); 126354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return IsInstructionIPut(instruction_->Opcode()) && 127354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko instruction_->VRegB_22c() == code_item_->registers_size_ - code_item_->ins_size_; 128354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 129354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 130354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool Matcher::DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size) { 131354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko Matcher matcher(code_item); 132354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko while (matcher.pos_ != size) { 133354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (!pattern[matcher.pos_](&matcher)) { 134354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 135354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 136354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 137354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 138354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 139354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 140354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// Used for a single invoke in a constructor. In that situation, the method verifier makes 141354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// sure we invoke a constructor either in the same class or superclass with at least "this". 142354efa6cdf558b2331e8fec539893fa51763806eVladimir MarkoArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_direct) 143354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko SHARED_REQUIRES(Locks::mutator_lock_) { 144354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT); 145354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK_EQ(invoke_direct->VRegC_35c(), 146354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko method->GetCodeItem()->registers_size_ - method->GetCodeItem()->ins_size_); 147354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint32_t method_index = invoke_direct->VRegB_35c(); 148354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); 149354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ArtMethod* target_method = 150354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko method->GetDexCache()->GetResolvedMethod(method_index, pointer_size); 151354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (kIsDebugBuild && target_method != nullptr) { 152354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko CHECK(!target_method->IsStatic()); 153354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko CHECK(target_method->IsConstructor()); 154354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko CHECK(target_method->GetDeclaringClass() == method->GetDeclaringClass() || 155354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko target_method->GetDeclaringClass() == method->GetDeclaringClass()->GetSuperClass()); 156354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 157354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return target_method; 158354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 159354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 160354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// Return the forwarded arguments and check that all remaining arguments are zero. 161354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// If the check fails, return static_cast<size_t>(-1). 162354efa6cdf558b2331e8fec539893fa51763806eVladimir Markosize_t CountForwardedConstructorArguments(const DexFile::CodeItem* code_item, 163354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko const Instruction* invoke_direct, 164354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint16_t zero_vreg_mask) { 165354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT); 166354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko size_t number_of_args = invoke_direct->VRegA_35c(); 167354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK_NE(number_of_args, 0u); 168354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint32_t args[Instruction::kMaxVarArgRegs]; 169354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko invoke_direct->GetVarArgs(args); 170354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint16_t this_vreg = args[0]; 171354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK_EQ(this_vreg, code_item->registers_size_ - code_item->ins_size_); // Checked by verifier. 172354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko size_t forwarded = 1u; 173354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko while (forwarded < number_of_args && 174354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko args[forwarded] == this_vreg + forwarded && 175354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko (zero_vreg_mask & (1u << args[forwarded])) == 0) { 176354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ++forwarded; 177354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 178354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko for (size_t i = forwarded; i != number_of_args; ++i) { 179354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if ((zero_vreg_mask & (1u << args[i])) == 0) { 180354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return static_cast<size_t>(-1); 181354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 182354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 183354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return forwarded; 184354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 185354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 186354efa6cdf558b2331e8fec539893fa51763806eVladimir Markouint16_t GetZeroVRegMask(const Instruction* const0) { 187354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(IsInstructionDirectConst(const0->Opcode())); 188354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK((const0->Opcode() == Instruction::CONST_WIDE) ? const0->VRegB_51l() == 0u 189354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko : const0->VRegB() == 0); 190354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint16_t base_mask = IsInstructionConstWide(const0->Opcode()) ? 3u : 1u; 191354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return base_mask << const0->VRegA(); 192354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 193354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 194354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// We limit the number of IPUTs storing parameters. There can be any number 195354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// of IPUTs that store the value 0 as they are useless in a constructor as 196354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// the object always starts zero-initialized. We also eliminate all but the 197354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// last store to any field as they are not observable; not even if the field 198354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// is volatile as no reference to the object can escape from a constructor 199354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko// with this pattern. 200354efa6cdf558b2331e8fec539893fa51763806eVladimir Markostatic constexpr size_t kMaxConstructorIPuts = 3u; 201354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 202354efa6cdf558b2331e8fec539893fa51763806eVladimir Markostruct ConstructorIPutData { 203354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ConstructorIPutData() : field_index(DexFile::kDexNoIndex16), arg(0u) { } 204354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 205354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint16_t field_index; 206354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint16_t arg; 207354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko}; 208354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 209354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool RecordConstructorIPut(ArtMethod* method, 210354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko const Instruction* new_iput, 211354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint16_t this_vreg, 212354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint16_t zero_vreg_mask, 213354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts]) 214354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko SHARED_REQUIRES(Locks::mutator_lock_) { 215354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(IsInstructionIPut(new_iput->Opcode())); 216354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint32_t field_index = new_iput->VRegC_22c(); 217354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); 218354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko mirror::DexCache* dex_cache = method->GetDexCache(); 219354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ArtField* field = dex_cache->GetResolvedField(field_index, pointer_size); 220354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (UNLIKELY(field == nullptr)) { 221354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 222354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 223354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Remove previous IPUT to the same field, if any. Different field indexes may refer 224354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // to the same field, so we need to compare resolved fields from the dex cache. 225354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko for (size_t old_pos = 0; old_pos != arraysize(iputs); ++old_pos) { 226354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (iputs[old_pos].field_index == DexFile::kDexNoIndex16) { 227354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko break; 228354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 229354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ArtField* f = dex_cache->GetResolvedField(iputs[old_pos].field_index, pointer_size); 230354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(f != nullptr); 231354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (f == field) { 232354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko auto back_it = std::copy(iputs + old_pos + 1, iputs + arraysize(iputs), iputs + old_pos); 233354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko *back_it = ConstructorIPutData(); 234354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko break; 235354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 236354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 237354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // If the stored value isn't zero, record the IPUT. 238354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if ((zero_vreg_mask & (1u << new_iput->VRegA_22c())) == 0u) { 239354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko size_t new_pos = 0; 240354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko while (new_pos != arraysize(iputs) && iputs[new_pos].field_index != DexFile::kDexNoIndex16) { 241354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ++new_pos; 242354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 243354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (new_pos == arraysize(iputs)) { 244354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; // Exceeded capacity of the output array. 245354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 246354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko iputs[new_pos].field_index = field_index; 247354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko iputs[new_pos].arg = new_iput->VRegA_22c() - this_vreg; 248354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 249354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 250354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 251354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 252354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool DoAnalyseConstructor(const DexFile::CodeItem* code_item, 253354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ArtMethod* method, 254354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts]) 255354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko SHARED_REQUIRES(Locks::mutator_lock_) { 256354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // On entry we should not have any IPUTs yet. 257354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK_EQ(0, std::count_if( 258354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko iputs, 259354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko iputs + arraysize(iputs), 260354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko [](const ConstructorIPutData& iput_data) { 261354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return iput_data.field_index != DexFile::kDexNoIndex16; 262354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko })); 263354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 264354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Limit the maximum number of code units we're willing to match. 265354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko static constexpr size_t kMaxCodeUnits = 16u; 266354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 267354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Limit the number of registers that the constructor may use to 16. 268354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Given that IPUTs must use low 16 registers and we do not match MOVEs, 269354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // this is a reasonable limitation. 270354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko static constexpr size_t kMaxVRegs = 16u; 271354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 272354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // We try to match a constructor that calls another constructor (either in 273354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // superclass or in the same class) with the same parameters, or with some 274354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // parameters truncated (allowed only for calls to superclass constructor) 275354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // or with extra parameters with value 0 (with any type, including null). 276354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // This call can be followed by optional IPUTs on "this" storing either one 277354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // of the parameters or 0 and the code must then finish with RETURN_VOID. 278354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // The called constructor must be either java.lang.Object.<init>() or it 279354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // must also match the same pattern. 280354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko static Matcher::MatchFn* const kConstructorPattern[] = { 281354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko &Matcher::Mark, 282354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko &Matcher::Repeated<&Matcher::Const0>, 283354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko &Matcher::Required<&Matcher::Opcode<Instruction::INVOKE_DIRECT>>, 284354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko &Matcher::Mark, 285354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko &Matcher::Repeated<&Matcher::Const0>, 286354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko &Matcher::Repeated<&Matcher::IPutOnThis>, 287354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko &Matcher::Required<&Matcher::Opcode<Instruction::RETURN_VOID>>, 288354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko }; 289354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 290354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(method != nullptr); 291354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(!method->IsStatic()); 292354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(method->IsConstructor()); 293354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(code_item != nullptr); 294354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (!method->GetDeclaringClass()->IsVerified() || 295354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko code_item->insns_size_in_code_units_ > kMaxCodeUnits || 296354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko code_item->registers_size_ > kMaxVRegs || 297354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko !Matcher::Match(code_item, kConstructorPattern)) { 298354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 299354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 300354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 301354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Verify the invoke, prevent a few odd cases and collect IPUTs. 302354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_; 303354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint16_t zero_vreg_mask = 0u; 304354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko for (const Instruction* instruction = Instruction::At(code_item->insns_); 305354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko instruction->Opcode() != Instruction::RETURN_VOID; 306354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko instruction = instruction->Next()) { 307354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (instruction->Opcode() == Instruction::INVOKE_DIRECT) { 308354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ArtMethod* target_method = GetTargetConstructor(method, instruction); 309354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (target_method == nullptr) { 310354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 311354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 312354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // We allow forwarding constructors only if they pass more arguments 313354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // to prevent infinite recursion. 314354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (target_method->GetDeclaringClass() == method->GetDeclaringClass() && 315354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko instruction->VRegA_35c() <= code_item->ins_size_) { 316354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 317354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 318354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko size_t forwarded = CountForwardedConstructorArguments(code_item, instruction, zero_vreg_mask); 319354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (forwarded == static_cast<size_t>(-1)) { 320354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 321354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 322354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (target_method->GetDeclaringClass()->IsObjectClass()) { 323141de8c4cf18923b4ee773a455102734ca9e4407Nicolas Geoffray DCHECK_EQ(Instruction::At(target_method->GetCodeItem()->insns_)->Opcode(), 324141de8c4cf18923b4ee773a455102734ca9e4407Nicolas Geoffray Instruction::RETURN_VOID); 325354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } else { 326354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko const DexFile::CodeItem* target_code_item = target_method->GetCodeItem(); 327354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (target_code_item == nullptr) { 328354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; // Native constructor? 329354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 330354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (!DoAnalyseConstructor(target_code_item, target_method, iputs)) { 331354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 332354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 333354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Prune IPUTs with zero input. 334354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko auto kept_end = std::remove_if( 335354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko iputs, 336354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko iputs + arraysize(iputs), 337354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko [forwarded](const ConstructorIPutData& iput_data) { 338354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return iput_data.arg >= forwarded; 339354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko }); 340354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko std::fill(kept_end, iputs + arraysize(iputs), ConstructorIPutData()); 341354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // If we have any IPUTs from the call, check that the target method is in the same 342354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // dex file (compare DexCache references), otherwise field_indexes would be bogus. 343354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (iputs[0].field_index != DexFile::kDexNoIndex16 && 344354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko target_method->GetDexCache() != method->GetDexCache()) { 345354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 346354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 347354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 348354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } else if (IsInstructionDirectConst(instruction->Opcode())) { 349354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko zero_vreg_mask |= GetZeroVRegMask(instruction); 350354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if ((zero_vreg_mask & (1u << this_vreg)) != 0u) { 351354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; // Overwriting `this` is unsupported. 352354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 353354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } else { 354354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(IsInstructionIPut(instruction->Opcode())); 355354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK_EQ(instruction->VRegB_22c(), this_vreg); 356354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (!RecordConstructorIPut(method, instruction, this_vreg, zero_vreg_mask, iputs)) { 357354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 358354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 359354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 360354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 361354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 362354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 363354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 364354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} // anonymous namespace 365354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 366354efa6cdf558b2331e8fec539893fa51763806eVladimir Markobool AnalyseConstructor(const DexFile::CodeItem* code_item, 367354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ArtMethod* method, 368354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko InlineMethod* result) 369354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko SHARED_REQUIRES(Locks::mutator_lock_) { 370354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko ConstructorIPutData iputs[kMaxConstructorIPuts]; 371354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (!DoAnalyseConstructor(code_item, method, iputs)) { 372354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 373354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 374354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko static_assert(kMaxConstructorIPuts == 3, "Unexpected limit"); // Code below depends on this. 375354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(iputs[0].field_index != DexFile::kDexNoIndex16 || 376354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko iputs[1].field_index == DexFile::kDexNoIndex16); 377354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(iputs[1].field_index != DexFile::kDexNoIndex16 || 378354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko iputs[2].field_index == DexFile::kDexNoIndex16); 379354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 380354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko#define STORE_IPUT(n) \ 381354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko do { \ 382354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko result->d.constructor_data.iput##n##_field_index = iputs[n].field_index; \ 383354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko result->d.constructor_data.iput##n##_arg = iputs[n].arg; \ 384354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } while (false) 385354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 386354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko STORE_IPUT(0); 387354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko STORE_IPUT(1); 388354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko STORE_IPUT(2); 389354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko#undef STORE_IPUT 390354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 391354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko result->opcode = kInlineOpConstructor; 392354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko result->flags = kInlineSpecial; 393354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko result->d.constructor_data.reserved = 0u; 394354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 395354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko} 396354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko 397575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET), "iget type"); 398575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_WIDE), "iget_wide type"); 399575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_OBJECT), 400575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe "iget_object type"); 401575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BOOLEAN), 402575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe "iget_boolean type"); 403575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BYTE), "iget_byte type"); 404575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_CHAR), "iget_char type"); 405575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_SHORT), "iget_short type"); 406575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT), "iput type"); 407575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_WIDE), "iput_wide type"); 408575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_OBJECT), 409575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe "iput_object type"); 410575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BOOLEAN), 411575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe "iput_boolean type"); 412575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BYTE), "iput_byte type"); 413575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_CHAR), "iput_char type"); 414575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_SHORT), "iput_short type"); 415575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET) == 416575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT), "iget/iput variant"); 417575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE) == 418575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE), "iget/iput_wide variant"); 419575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT) == 420575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT), "iget/iput_object variant"); 421575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BOOLEAN) == 422575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BOOLEAN), "iget/iput_boolean variant"); 423575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BYTE) == 424575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BYTE), "iget/iput_byte variant"); 425575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_CHAR) == 426575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_CHAR), "iget/iput_char variant"); 427575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) == 428575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant"); 429e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 4302c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// This is used by compiler and debugger. We look into the dex cache for resolved methods and 4312c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// fields. However, in the context of the debugger, not all methods and fields are resolved. Since 4322c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// we need to be able to detect possibly inlined method, we pass a null inline method to indicate 4332c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// we don't want to take unresolved methods and fields into account during analysis. 434e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseMethodCode(verifier::MethodVerifier* verifier, 435be10e8e99a78caae01fb65769218800d465144aeVladimir Marko InlineMethod* result) { 4362c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz DCHECK(verifier != nullptr); 437e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier if (!Runtime::Current()->UseJit()) { 438be10e8e99a78caae01fb65769218800d465144aeVladimir Marko DCHECK_EQ(verifier->CanLoadClasses(), result != nullptr); 439be10e8e99a78caae01fb65769218800d465144aeVladimir Marko } 440be10e8e99a78caae01fb65769218800d465144aeVladimir Marko 441be10e8e99a78caae01fb65769218800d465144aeVladimir Marko // Note: verifier->GetMethod() may be null. 442be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return AnalyseMethodCode(verifier->CodeItem(), 443be10e8e99a78caae01fb65769218800d465144aeVladimir Marko verifier->GetMethodReference(), 444be10e8e99a78caae01fb65769218800d465144aeVladimir Marko (verifier->GetAccessFlags() & kAccStatic) != 0u, 445be10e8e99a78caae01fb65769218800d465144aeVladimir Marko verifier->GetMethod(), 446be10e8e99a78caae01fb65769218800d465144aeVladimir Marko result); 447be10e8e99a78caae01fb65769218800d465144aeVladimir Marko} 448be10e8e99a78caae01fb65769218800d465144aeVladimir Marko 449be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) { 450be10e8e99a78caae01fb65769218800d465144aeVladimir Marko const DexFile::CodeItem* code_item = method->GetCodeItem(); 451be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (code_item == nullptr) { 452be10e8e99a78caae01fb65769218800d465144aeVladimir Marko // Native or abstract. 453be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return false; 454e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier } 455be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return AnalyseMethodCode( 456be10e8e99a78caae01fb65769218800d465144aeVladimir Marko code_item, method->ToMethodReference(), method->IsStatic(), method, result); 457be10e8e99a78caae01fb65769218800d465144aeVladimir Marko} 458be10e8e99a78caae01fb65769218800d465144aeVladimir Marko 459be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item, 460be10e8e99a78caae01fb65769218800d465144aeVladimir Marko const MethodReference& method_ref, 461be10e8e99a78caae01fb65769218800d465144aeVladimir Marko bool is_static, 462be10e8e99a78caae01fb65769218800d465144aeVladimir Marko ArtMethod* method, 463be10e8e99a78caae01fb65769218800d465144aeVladimir Marko InlineMethod* result) { 464e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // We currently support only plain return or 2-instruction methods. 465e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 466e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_NE(code_item->insns_size_in_code_units_, 0u); 467e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 468e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 469e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 470e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko switch (opcode) { 471e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_VOID: 4729f35ccd3880e2d4d03dce7d7edb4307fadddf62bVladimir Marko if (result != nullptr) { 473be10e8e99a78caae01fb65769218800d465144aeVladimir Marko result->opcode = kInlineOpNop; 474be10e8e99a78caae01fb65769218800d465144aeVladimir Marko result->flags = kInlineSpecial; 475be10e8e99a78caae01fb65769218800d465144aeVladimir Marko result->d.data = 0u; 4762c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 477e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 478e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN: 479e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_OBJECT: 480e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_WIDE: 481be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return AnalyseReturnMethod(code_item, result); 482e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST: 483e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_4: 484e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_16: 485e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_HIGH16: 486e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // TODO: Support wide constants (RETURN_WIDE). 487354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (AnalyseConstMethod(code_item, result)) { 488354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 489354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 490354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko FALLTHROUGH_INTENDED; 491354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::CONST_WIDE: 492354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::CONST_WIDE_16: 493354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::CONST_WIDE_32: 494354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::CONST_WIDE_HIGH16: 495354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::INVOKE_DIRECT: 496354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (method != nullptr && !method->IsStatic() && method->IsConstructor()) { 497354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return AnalyseConstructor(code_item, method, result); 498354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 499354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 500e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET: 501e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_OBJECT: 502e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BOOLEAN: 503e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BYTE: 504e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_CHAR: 505e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_SHORT: 506e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_WIDE: 507e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // TODO: Add handling for JIT. 508e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IGET_QUICK: 509e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IGET_WIDE_QUICK: 510e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IGET_OBJECT_QUICK: 511be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return AnalyseIGetMethod(code_item, method_ref, is_static, method, result); 512e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT: 513e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_OBJECT: 514e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BOOLEAN: 515e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BYTE: 516e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_CHAR: 517e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_SHORT: 518e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_WIDE: 519e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // TODO: Add handling for JIT. 520e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IPUT_QUICK: 521e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IPUT_WIDE_QUICK: 522e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IPUT_OBJECT_QUICK: 523be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return AnalyseIPutMethod(code_item, method_ref, is_static, method, result); 524e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko default: 525e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 526e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 527e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 528e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 529c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Markobool InlineMethodAnalyser::IsSyntheticAccessor(MethodReference ref) { 530c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko const DexFile::MethodId& method_id = ref.dex_file->GetMethodId(ref.dex_method_index); 531c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko const char* method_name = ref.dex_file->GetMethodName(method_id); 532d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko // javac names synthetic accessors "access$nnn", 533d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko // jack names them "-getN", "-putN", "-wrapN". 534d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko return strncmp(method_name, "access$", strlen("access$")) == 0 || 535d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko strncmp(method_name, "-", strlen("-")) == 0; 536c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko} 537c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko 538e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item, 539e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 540e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = Instruction::At(code_item->insns_); 541e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 542e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t reg = return_instruction->VRegA_11x(); 543e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 544e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(reg, arg_start); 545e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg, 546e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 547e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 5482c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 5492c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpReturnArg; 5502c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 5512c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineReturnArgData* data = &result->d.return_data; 5522c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->arg = reg - arg_start; 5532c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u; 5542c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u; 5552c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->reserved = 0u; 5562c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->reserved2 = 0u; 5572c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 558e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 559e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 560e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 561e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item, 562e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 563e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 564e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 565e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 566e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN && 567e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return_opcode != Instruction::RETURN_OBJECT) { 568e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 569e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 570e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 57129a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers int32_t return_reg = return_instruction->VRegA_11x(); 572e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_reg, code_item->registers_size_); 573e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 57429a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers int32_t const_value = instruction->VRegB(); 575e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (instruction->Opcode() == Instruction::CONST_HIGH16) { 57629a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers const_value <<= 16; 577e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 57829a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers DCHECK_LT(instruction->VRegA(), code_item->registers_size_); 57929a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers if (instruction->VRegA() != return_reg) { 580e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value set by const? 581e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 58229a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers if (return_opcode == Instruction::RETURN_OBJECT && const_value != 0) { 583e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Returning non-null reference constant? 584e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 5852c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 5862c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpNonWideConst; 5872c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 58829a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers result->d.data = static_cast<uint64_t>(const_value); 5892c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 590e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 591e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 592e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 593be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item, 594be10e8e99a78caae01fb65769218800d465144aeVladimir Marko const MethodReference& method_ref, 595be10e8e99a78caae01fb65769218800d465144aeVladimir Marko bool is_static, 596be10e8e99a78caae01fb65769218800d465144aeVladimir Marko ArtMethod* method, 597e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 598e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 599e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 600e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIGet(opcode)); 601e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 602e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 603e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 604e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!(return_opcode == Instruction::RETURN_WIDE && opcode == Instruction::IGET_WIDE) && 605e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT) && 606e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN && opcode != Instruction::IGET_WIDE && 607e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko opcode != Instruction::IGET_OBJECT)) { 608e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 609e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 610e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 611e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 612e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg, 613e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 614e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 615e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t dst_reg = instruction->VRegA_22c(); 616e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 617e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 618e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 619e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 620e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 621e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t object_arg = object_reg - arg_start; 622e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 623e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_); 624e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (dst_reg != return_reg) { 625e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value retrieved by IGET? 626e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 627e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 628be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (is_static || object_arg != 0u) { 629c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE). 630c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 631be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (!IsSyntheticAccessor(method_ref)) { 632c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko return false; 633c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko } 634e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 635e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 636e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // InlineIGetIPutData::object_arg is only 4 bits wide. 637e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxObjectArg = 15u; 638e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (object_arg > kMaxObjectArg) { 639e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 640e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 641e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 6422c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 6432c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineIGetIPutData* data = &result->d.ifield_data; 644be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (!ComputeSpecialAccessorInfo(method, field_idx, false, data)) { 6452c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz return false; 6462c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 6472c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpIGet; 6482c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 6492c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->op_variant = IGetVariant(opcode); 650be10e8e99a78caae01fb65769218800d465144aeVladimir Marko data->method_is_static = is_static ? 1u : 0u; 651e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->object_arg = object_arg; // Allow IGET on any register, not just "this". 652c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko data->src_arg = 0u; 653e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->return_arg_plus1 = 0u; 654e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 655e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 656e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 657e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 658be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item, 659be10e8e99a78caae01fb65769218800d465144aeVladimir Marko const MethodReference& method_ref, 660be10e8e99a78caae01fb65769218800d465144aeVladimir Marko bool is_static, 661be10e8e99a78caae01fb65769218800d465144aeVladimir Marko ArtMethod* method, 662e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 663e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 664e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 665e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIPut(opcode)); 666e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 667e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 668e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 669e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 670e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint16_t return_arg_plus1 = 0u; 671e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN_VOID) { 672e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (return_opcode != Instruction::RETURN && 673e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_opcode != Instruction::RETURN_OBJECT && 674e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_opcode != Instruction::RETURN_WIDE) { 675e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 676e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 677e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // Returning an argument. 678e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 679e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko DCHECK_GE(return_reg, arg_start); 680e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg, 681e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko code_item->registers_size_); 682e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_arg_plus1 = return_reg - arg_start + 1u; 683e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 684e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 685e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t src_reg = instruction->VRegA_22c(); 686e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 687e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 688e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 689e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 690e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(src_reg, arg_start); 691e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_); 692e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t object_arg = object_reg - arg_start; 693e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t src_arg = src_reg - arg_start; 694e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 695be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (is_static || object_arg != 0u) { 696c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE). 697c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 698be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (!IsSyntheticAccessor(method_ref)) { 699c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko return false; 700c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko } 701e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 702e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 703e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // InlineIGetIPutData::object_arg/src_arg/return_arg_plus1 are each only 4 bits wide. 704e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxObjectArg = 15u; 705e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxSrcArg = 15u; 706e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxReturnArgPlus1 = 15u; 707e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (object_arg > kMaxObjectArg || src_arg > kMaxSrcArg || return_arg_plus1 > kMaxReturnArgPlus1) { 708e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 709e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 710e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 7112c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 7122c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineIGetIPutData* data = &result->d.ifield_data; 713be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (!ComputeSpecialAccessorInfo(method, field_idx, true, data)) { 7142c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz return false; 7152c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 7162c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpIPut; 7172c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 7182c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->op_variant = IPutVariant(opcode); 719be10e8e99a78caae01fb65769218800d465144aeVladimir Marko data->method_is_static = is_static ? 1u : 0u; 720e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->object_arg = object_arg; // Allow IPUT on any register, not just "this". 721e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->src_arg = src_arg; 722e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->return_arg_plus1 = return_arg_plus1; 723e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 724e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 725e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 726e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 727be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::ComputeSpecialAccessorInfo(ArtMethod* method, 728be10e8e99a78caae01fb65769218800d465144aeVladimir Marko uint32_t field_idx, 729be10e8e99a78caae01fb65769218800d465144aeVladimir Marko bool is_put, 730e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineIGetIPutData* result) { 731be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (method == nullptr) { 732be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return false; 733be10e8e99a78caae01fb65769218800d465144aeVladimir Marko } 734be10e8e99a78caae01fb65769218800d465144aeVladimir Marko mirror::DexCache* dex_cache = method->GetDexCache(); 735be10e8e99a78caae01fb65769218800d465144aeVladimir Marko size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); 736be10e8e99a78caae01fb65769218800d465144aeVladimir Marko ArtField* field = dex_cache->GetResolvedField(field_idx, pointer_size); 737be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (field == nullptr || field->IsStatic()) { 738e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 739e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 740e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::Class* method_class = method->GetDeclaringClass(); 741e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::Class* field_class = field->GetDeclaringClass(); 742e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) || 743e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko (is_put && field->IsFinal() && method_class != field_class)) { 744e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 745e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 746e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(field->GetOffset().Int32Value(), 0); 7478b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko // Do not interleave function calls with bit field writes to placate valgrind. Bug: 27552451. 7488b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko uint32_t field_offset = field->GetOffset().Uint32Value(); 7498b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko bool is_volatile = field->IsVolatile(); 750e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->field_idx = field_idx; 7518b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko result->field_offset = field_offset; 7528b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko result->is_volatile = is_volatile ? 1u : 0u; 753e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 754e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 755e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 756e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} // namespace art 757