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