inline_method_analyser.cc revision e3e0260c23d8999b9433715ac7ee5296ee2fd633
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" 18e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "dex_instruction.h" 19e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "dex_instruction-inl.h" 20e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/art_field.h" 21e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/art_field-inl.h" 22e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/art_method.h" 23e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/art_method-inl.h" 24e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/class.h" 25e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/class-inl.h" 26e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/dex_cache.h" 27e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/dex_cache-inl.h" 28e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "verifier/method_verifier.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 38e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET), 39e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iget_type); 40e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_WIDE), 41e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iget_wide_type); 42e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_OBJECT), 43e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iget_object_type); 44e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BOOLEAN), 45e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iget_boolean_type); 46e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BYTE), 47e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iget_byte_type); 48e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_CHAR), 49e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iget_char_type); 50e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_SHORT), 51e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iget_short_type); 52e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 53e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT), 54e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iput_type); 55e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_WIDE), 56e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iput_wide_type); 57e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_OBJECT), 58e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iput_object_type); 59e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BOOLEAN), 60e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iput_boolean_type); 61e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BYTE), 62e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iput_byte_type); 63e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_CHAR), 64e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iput_char_type); 65e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_SHORT), 66e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko check_iput_short_type); 67e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 68e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET) == 69e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethodAnalyser::IPutVariant(Instruction::IPUT), check_iget_iput_variant); 70e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE) == 71e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE), check_iget_iput_wide_variant); 72e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT) == 73e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT), check_iget_iput_object_variant); 74e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BOOLEAN) == 75e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BOOLEAN), check_iget_iput_boolean_variant); 76e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BYTE) == 77e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BYTE), check_iget_iput_byte_variant); 78e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_CHAR) == 79e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethodAnalyser::IPutVariant(Instruction::IPUT_CHAR), check_iget_iput_char_variant); 80e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir MarkoCOMPILE_ASSERT(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) == 81e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), check_iget_iput_short_variant); 82e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 83e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseMethodCode(verifier::MethodVerifier* verifier, 84e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* method) { 85e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // We currently support only plain return or 2-instruction methods. 86e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 87e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const DexFile::CodeItem* code_item = verifier->CodeItem(); 88e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_NE(code_item->insns_size_in_code_units_, 0u); 89e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 90e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 91e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 92e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko switch (opcode) { 93e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_VOID: 94e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko method->opcode = kInlineOpNop; 95e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko method->flags = kInlineSpecial; 96e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko method->d.data = 0u; 97e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 98e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN: 99e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_OBJECT: 100e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_WIDE: 101e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseReturnMethod(code_item, method); 102e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST: 103e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_4: 104e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_16: 105e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_HIGH16: 106e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // TODO: Support wide constants (RETURN_WIDE). 107e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseConstMethod(code_item, method); 108e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET: 109e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_OBJECT: 110e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BOOLEAN: 111e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BYTE: 112e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_CHAR: 113e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_SHORT: 114e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_WIDE: 115e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseIGetMethod(verifier, method); 116e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT: 117e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_OBJECT: 118e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BOOLEAN: 119e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BYTE: 120e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_CHAR: 121e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_SHORT: 122e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_WIDE: 123e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseIPutMethod(verifier, method); 124e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko default: 125e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 126e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 127e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 128e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 129e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item, 130e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 131e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = Instruction::At(code_item->insns_); 132e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 133e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t reg = return_instruction->VRegA_11x(); 134e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 135e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(reg, arg_start); 136e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg, 137e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 138e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 139e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->opcode = kInlineOpReturnArg; 140e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->flags = kInlineSpecial; 141e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineReturnArgData* data = &result->d.return_data; 142e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->arg = reg - arg_start; 143e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u; 144e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u; 145e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->reserved = 0u; 146e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->reserved2 = 0u; 147e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 148e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 149e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 150e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item, 151e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 152e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 153e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 154e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 155e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN && 156e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return_opcode != Instruction::RETURN_OBJECT) { 157e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 158e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 159e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 160e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 161e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_reg, code_item->registers_size_); 162e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 163e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t vA, vB, dummy; 164e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint64_t dummy_wide; 165e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko instruction->Decode(vA, vB, dummy_wide, dummy, nullptr); 166e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (instruction->Opcode() == Instruction::CONST_HIGH16) { 167e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko vB <<= 16; 168e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 169e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(vA, code_item->registers_size_); 170e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (vA != return_reg) { 171e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value set by const? 172e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 173e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) { 174e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Returning non-null reference constant? 175e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 176e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->opcode = kInlineOpNonWideConst; 177e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->flags = kInlineSpecial; 178e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->d.data = static_cast<uint64_t>(vB); 179e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 180e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 181e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 182e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseIGetMethod(verifier::MethodVerifier* verifier, 183e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 184e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const DexFile::CodeItem* code_item = verifier->CodeItem(); 185e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 186e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 187e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIGet(opcode)); 188e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 189e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 190e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 191e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!(return_opcode == Instruction::RETURN_WIDE && opcode == Instruction::IGET_WIDE) && 192e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT) && 193e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN && opcode != Instruction::IGET_WIDE && 194e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko opcode != Instruction::IGET_OBJECT)) { 195e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 196e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 197e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 198e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 199e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg, 200e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 201e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 202e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t dst_reg = instruction->VRegA_22c(); 203e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 204e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 205e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 206e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 207e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 208e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_); 209e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (dst_reg != return_reg) { 210e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value retrieved by IGET? 211e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 212e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 213e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) { 214e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // TODO: Support inlining IGET on other register than "this". 215e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 216e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 217e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 218e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!ComputeSpecialAccessorInfo(field_idx, false, verifier, &result->d.ifield_data)) { 219e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 220e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 221e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 222e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->opcode = kInlineOpIGet; 223e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->flags = kInlineSpecial; 224e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineIGetIPutData* data = &result->d.ifield_data; 225e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->op_variant = IGetVariant(opcode); 226e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->object_arg = object_reg - arg_start; // Allow IGET on any register, not just "this". 227e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->src_arg = 0; 228e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0; 229e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->reserved = 0; 230e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 231e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 232e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 233e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseIPutMethod(verifier::MethodVerifier* verifier, 234e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 235e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const DexFile::CodeItem* code_item = verifier->CodeItem(); 236e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 237e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 238e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIPut(opcode)); 239e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 240e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 241e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 242e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN_VOID) { 243e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // TODO: Support returning an argument. 244e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // This is needed by builder classes and generated accessor setters. 245e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // builder.setX(value): iput value, this, fieldX; return-object this; 246e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // object.access$nnn(value): iput value, this, fieldX; return value; 247e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // Use InlineIGetIPutData::reserved to hold the information. 248e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 249e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 250e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 251e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t src_reg = instruction->VRegA_22c(); 252e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 253e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 254e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 255e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 256e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 257e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(src_reg, arg_start); 258e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_); 259e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 260e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) { 261e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // TODO: Support inlining IPUT on other register than "this". 262e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 263e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 264e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 265e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!ComputeSpecialAccessorInfo(field_idx, true, verifier, &result->d.ifield_data)) { 266e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 267e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 268e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 269e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->opcode = kInlineOpIPut; 270e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->flags = kInlineSpecial; 271e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineIGetIPutData* data = &result->d.ifield_data; 272e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->op_variant = IPutVariant(opcode); 273e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->object_arg = object_reg - arg_start; // Allow IPUT on any register, not just "this". 274e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->src_arg = src_reg - arg_start; 275e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0; 276e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko data->reserved = 0; 277e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 278e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 279e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 280e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put, 281e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko verifier::MethodVerifier* verifier, 282e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineIGetIPutData* result) { 283e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::DexCache* dex_cache = verifier->GetDexCache(); 284e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t method_idx = verifier->GetMethodReference().dex_method_index; 285e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx); 286e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::ArtField* field = dex_cache->GetResolvedField(field_idx); 287e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (method == nullptr || field == nullptr || field->IsStatic()) { 288e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 289e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 290e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::Class* method_class = method->GetDeclaringClass(); 291e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::Class* field_class = field->GetDeclaringClass(); 292e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) || 293e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko (is_put && field->IsFinal() && method_class != field_class)) { 294e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 295e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 296e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(field->GetOffset().Int32Value(), 0); 297e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->field_idx = field_idx; 298e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->field_offset = field->GetOffset().Int32Value(); 299e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->is_volatile = field->IsVolatile(); 300e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 301e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 302e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 303e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} // namespace art 304