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 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) 143bdf7f1c3ab65ccb70f62db5ab31dba060632d458Andreas Gampe REQUIRES_SHARED(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(); 148542451cc546779f5c67840e105c51205a1b0a8fdAndreas Gampe PointerSize 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]) 214bdf7f1c3ab65ccb70f62db5ab31dba060632d458Andreas Gampe REQUIRES_SHARED(Locks::mutator_lock_) { 215354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko DCHECK(IsInstructionIPut(new_iput->Opcode())); 216354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko uint32_t field_index = new_iput->VRegC_22c(); 217f44d36c8423f81cbb5e9f55d8813e26ffa1a7f3bVladimir Marko ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 218f44d36c8423f81cbb5e9f55d8813e26ffa1a7f3bVladimir Marko ArtField* field = class_linker->LookupResolvedField(field_index, method, /* is_static */ false); 219354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (UNLIKELY(field == nullptr)) { 220354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 221354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 222354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // Remove previous IPUT to the same field, if any. Different field indexes may refer 223354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko // to the same field, so we need to compare resolved fields from the dex cache. 224354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko for (size_t old_pos = 0; old_pos != arraysize(iputs); ++old_pos) { 225354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (iputs[old_pos].field_index == DexFile::kDexNoIndex16) { 226354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko break; 227354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 228f44d36c8423f81cbb5e9f55d8813e26ffa1a7f3bVladimir Marko ArtField* f = class_linker->LookupResolvedField(iputs[old_pos].field_index, 229f44d36c8423f81cbb5e9f55d8813e26ffa1a7f3bVladimir Marko method, 230f44d36c8423f81cbb5e9f55d8813e26ffa1a7f3bVladimir Marko /* is_static */ false); 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]) 256bdf7f1c3ab65ccb70f62db5ab31dba060632d458Andreas Gampe REQUIRES_SHARED(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) 370bdf7f1c3ab65ccb70f62db5ab31dba060632d458Andreas Gampe REQUIRES_SHARED(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->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 430be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) { 431be10e8e99a78caae01fb65769218800d465144aeVladimir Marko const DexFile::CodeItem* code_item = method->GetCodeItem(); 432be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (code_item == nullptr) { 433be10e8e99a78caae01fb65769218800d465144aeVladimir Marko // Native or abstract. 434be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return false; 435e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier } 436be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return AnalyseMethodCode( 437be10e8e99a78caae01fb65769218800d465144aeVladimir Marko code_item, method->ToMethodReference(), method->IsStatic(), method, result); 438be10e8e99a78caae01fb65769218800d465144aeVladimir Marko} 439be10e8e99a78caae01fb65769218800d465144aeVladimir Marko 440be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item, 441be10e8e99a78caae01fb65769218800d465144aeVladimir Marko const MethodReference& method_ref, 442be10e8e99a78caae01fb65769218800d465144aeVladimir Marko bool is_static, 443be10e8e99a78caae01fb65769218800d465144aeVladimir Marko ArtMethod* method, 444be10e8e99a78caae01fb65769218800d465144aeVladimir Marko InlineMethod* result) { 445e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // We currently support only plain return or 2-instruction methods. 446e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 447e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_NE(code_item->insns_size_in_code_units_, 0u); 448e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 449e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 450e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 451e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko switch (opcode) { 452e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_VOID: 4539f35ccd3880e2d4d03dce7d7edb4307fadddf62bVladimir Marko if (result != nullptr) { 454be10e8e99a78caae01fb65769218800d465144aeVladimir Marko result->opcode = kInlineOpNop; 455be10e8e99a78caae01fb65769218800d465144aeVladimir Marko result->d.data = 0u; 4562c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 457e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 458e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN: 459e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_OBJECT: 460e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_WIDE: 461be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return AnalyseReturnMethod(code_item, result); 462e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST: 463e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_4: 464e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_16: 465e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_HIGH16: 466e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // TODO: Support wide constants (RETURN_WIDE). 467354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (AnalyseConstMethod(code_item, result)) { 468354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return true; 469354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 470354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko FALLTHROUGH_INTENDED; 471354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::CONST_WIDE: 472354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::CONST_WIDE_16: 473354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::CONST_WIDE_32: 474354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::CONST_WIDE_HIGH16: 475354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko case Instruction::INVOKE_DIRECT: 476354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko if (method != nullptr && !method->IsStatic() && method->IsConstructor()) { 477354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return AnalyseConstructor(code_item, method, result); 478354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko } 479354efa6cdf558b2331e8fec539893fa51763806eVladimir Marko return false; 480e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET: 481e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_OBJECT: 482e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BOOLEAN: 483e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BYTE: 484e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_CHAR: 485e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_SHORT: 486e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_WIDE: 487e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // TODO: Add handling for JIT. 488e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IGET_QUICK: 489e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IGET_WIDE_QUICK: 490e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IGET_OBJECT_QUICK: 491be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return AnalyseIGetMethod(code_item, method_ref, is_static, method, result); 492e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT: 493e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_OBJECT: 494e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BOOLEAN: 495e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BYTE: 496e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_CHAR: 497e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_SHORT: 498e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_WIDE: 499e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // TODO: Add handling for JIT. 500e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IPUT_QUICK: 501e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IPUT_WIDE_QUICK: 502e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IPUT_OBJECT_QUICK: 503be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return AnalyseIPutMethod(code_item, method_ref, is_static, method, result); 504e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko default: 505e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 506e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 507e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 508e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 509c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Markobool InlineMethodAnalyser::IsSyntheticAccessor(MethodReference ref) { 510c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko const DexFile::MethodId& method_id = ref.dex_file->GetMethodId(ref.dex_method_index); 511c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko const char* method_name = ref.dex_file->GetMethodName(method_id); 512d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko // javac names synthetic accessors "access$nnn", 513d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko // jack names them "-getN", "-putN", "-wrapN". 514d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko return strncmp(method_name, "access$", strlen("access$")) == 0 || 515d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko strncmp(method_name, "-", strlen("-")) == 0; 516c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko} 517c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko 518e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item, 519e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 520e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = Instruction::At(code_item->insns_); 521e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 522e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t reg = return_instruction->VRegA_11x(); 523e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 524e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(reg, arg_start); 525e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg, 526e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 527e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 5282c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 5292c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpReturnArg; 5302c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineReturnArgData* data = &result->d.return_data; 5312c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->arg = reg - arg_start; 5322c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u; 5332c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u; 5342c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->reserved = 0u; 5352c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->reserved2 = 0u; 5362c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 537e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 538e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 539e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 540e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item, 541e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 542e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 543e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 544e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 545e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN && 546e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return_opcode != Instruction::RETURN_OBJECT) { 547e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 548e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 549e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 55029a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers int32_t return_reg = return_instruction->VRegA_11x(); 551e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_reg, code_item->registers_size_); 552e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 55329a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers int32_t const_value = instruction->VRegB(); 554e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (instruction->Opcode() == Instruction::CONST_HIGH16) { 55529a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers const_value <<= 16; 556e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 55729a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers DCHECK_LT(instruction->VRegA(), code_item->registers_size_); 55829a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers if (instruction->VRegA() != return_reg) { 559e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value set by const? 560e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 56129a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers if (return_opcode == Instruction::RETURN_OBJECT && const_value != 0) { 562e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Returning non-null reference constant? 563e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 5642c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 5652c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpNonWideConst; 56629a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers result->d.data = static_cast<uint64_t>(const_value); 5672c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 568e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 569e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 570e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 571be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item, 572be10e8e99a78caae01fb65769218800d465144aeVladimir Marko const MethodReference& method_ref, 573be10e8e99a78caae01fb65769218800d465144aeVladimir Marko bool is_static, 574be10e8e99a78caae01fb65769218800d465144aeVladimir Marko ArtMethod* method, 575e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 576e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 577e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 578e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIGet(opcode)); 579e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 580e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 581e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 582e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!(return_opcode == Instruction::RETURN_WIDE && opcode == Instruction::IGET_WIDE) && 583e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT) && 584e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN && opcode != Instruction::IGET_WIDE && 585e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko opcode != Instruction::IGET_OBJECT)) { 586e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 587e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 588e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 589e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 590e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg, 591e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 592e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 593e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t dst_reg = instruction->VRegA_22c(); 594e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 595e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 596e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 597e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 598e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 599e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t object_arg = object_reg - arg_start; 600e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 601e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_); 602e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (dst_reg != return_reg) { 603e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value retrieved by IGET? 604e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 605e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 606be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (is_static || object_arg != 0u) { 607c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE). 608c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 609be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (!IsSyntheticAccessor(method_ref)) { 610c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko return false; 611c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko } 612e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 613e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 614e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // InlineIGetIPutData::object_arg is only 4 bits wide. 615e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxObjectArg = 15u; 616e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (object_arg > kMaxObjectArg) { 617e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 618e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 619e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 6202c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 6212c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineIGetIPutData* data = &result->d.ifield_data; 622be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (!ComputeSpecialAccessorInfo(method, field_idx, false, data)) { 6232c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz return false; 6242c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 6252c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpIGet; 6262c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->op_variant = IGetVariant(opcode); 627be10e8e99a78caae01fb65769218800d465144aeVladimir Marko data->method_is_static = is_static ? 1u : 0u; 628e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->object_arg = object_arg; // Allow IGET on any register, not just "this". 629c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko data->src_arg = 0u; 630e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->return_arg_plus1 = 0u; 631e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 632e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 633e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 634e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 635be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item, 636be10e8e99a78caae01fb65769218800d465144aeVladimir Marko const MethodReference& method_ref, 637be10e8e99a78caae01fb65769218800d465144aeVladimir Marko bool is_static, 638be10e8e99a78caae01fb65769218800d465144aeVladimir Marko ArtMethod* method, 639e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 640e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 641e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 642e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIPut(opcode)); 643e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 644e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 645e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 646e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 647e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint16_t return_arg_plus1 = 0u; 648e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN_VOID) { 649e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (return_opcode != Instruction::RETURN && 650e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_opcode != Instruction::RETURN_OBJECT && 651e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_opcode != Instruction::RETURN_WIDE) { 652e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 653e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 654e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // Returning an argument. 655e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 656e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko DCHECK_GE(return_reg, arg_start); 657e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg, 658e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko code_item->registers_size_); 659e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_arg_plus1 = return_reg - arg_start + 1u; 660e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 661e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 662e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t src_reg = instruction->VRegA_22c(); 663e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 664e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 665e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 666e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 667e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(src_reg, arg_start); 668e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_); 669e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t object_arg = object_reg - arg_start; 670e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t src_arg = src_reg - arg_start; 671e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 672be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (is_static || object_arg != 0u) { 673c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE). 674c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 675be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (!IsSyntheticAccessor(method_ref)) { 676c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko return false; 677c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko } 678e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 679e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 680e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // InlineIGetIPutData::object_arg/src_arg/return_arg_plus1 are each only 4 bits wide. 681e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxObjectArg = 15u; 682e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxSrcArg = 15u; 683e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxReturnArgPlus1 = 15u; 684e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (object_arg > kMaxObjectArg || src_arg > kMaxSrcArg || return_arg_plus1 > kMaxReturnArgPlus1) { 685e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 686e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 687e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 6882c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 6892c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineIGetIPutData* data = &result->d.ifield_data; 690be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (!ComputeSpecialAccessorInfo(method, field_idx, true, data)) { 6912c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz return false; 6922c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 6932c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpIPut; 6942c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->op_variant = IPutVariant(opcode); 695be10e8e99a78caae01fb65769218800d465144aeVladimir Marko data->method_is_static = is_static ? 1u : 0u; 696e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->object_arg = object_arg; // Allow IPUT on any register, not just "this". 697e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->src_arg = src_arg; 698e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->return_arg_plus1 = return_arg_plus1; 699e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 700e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 701e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 702e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 703be10e8e99a78caae01fb65769218800d465144aeVladimir Markobool InlineMethodAnalyser::ComputeSpecialAccessorInfo(ArtMethod* method, 704be10e8e99a78caae01fb65769218800d465144aeVladimir Marko uint32_t field_idx, 705be10e8e99a78caae01fb65769218800d465144aeVladimir Marko bool is_put, 706e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineIGetIPutData* result) { 707be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (method == nullptr) { 708be10e8e99a78caae01fb65769218800d465144aeVladimir Marko return false; 709be10e8e99a78caae01fb65769218800d465144aeVladimir Marko } 710f44d36c8423f81cbb5e9f55d8813e26ffa1a7f3bVladimir Marko ObjPtr<mirror::DexCache> dex_cache = method->GetDexCache(); 711f44d36c8423f81cbb5e9f55d8813e26ffa1a7f3bVladimir Marko ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); 712f44d36c8423f81cbb5e9f55d8813e26ffa1a7f3bVladimir Marko ArtField* field = class_linker->LookupResolvedField(field_idx, method, /* is_static */ false); 713be10e8e99a78caae01fb65769218800d465144aeVladimir Marko if (field == nullptr || field->IsStatic()) { 714e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 715e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 7163398c7874e002beaa6c2b2fadf183e7d1ddad23aMathieu Chartier ObjPtr<mirror::Class> method_class = method->GetDeclaringClass(); 7173398c7874e002beaa6c2b2fadf183e7d1ddad23aMathieu Chartier ObjPtr<mirror::Class> field_class = field->GetDeclaringClass(); 718e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) || 719e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko (is_put && field->IsFinal() && method_class != field_class)) { 720e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 721e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 722e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(field->GetOffset().Int32Value(), 0); 7238b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko // Do not interleave function calls with bit field writes to placate valgrind. Bug: 27552451. 7248b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko uint32_t field_offset = field->GetOffset().Uint32Value(); 7258b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko bool is_volatile = field->IsVolatile(); 726e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->field_idx = field_idx; 7278b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko result->field_offset = field_offset; 7288b3f835f0cca5db53a727d1d77fc6c2430d53d51Vladimir Marko result->is_volatile = is_volatile ? 1u : 0u; 729e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 730e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 731e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 732e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} // namespace art 733