inline_method_analyser.cc revision 29a2648821ea4d0b5d3aecb9f835822fdfe6faa1
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 832c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// This is used by compiler and debugger. We look into the dex cache for resolved methods and 842c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// fields. However, in the context of the debugger, not all methods and fields are resolved. Since 852c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// we need to be able to detect possibly inlined method, we pass a null inline method to indicate 862c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// we don't want to take unresolved methods and fields into account during analysis. 87e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseMethodCode(verifier::MethodVerifier* verifier, 88e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* method) { 892c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz DCHECK(verifier != nullptr); 902c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz DCHECK_EQ(Runtime::Current()->IsCompiler(), method != nullptr); 912c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz DCHECK_EQ(verifier->CanLoadClasses(), method != nullptr); 92e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // We currently support only plain return or 2-instruction methods. 93e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 94e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const DexFile::CodeItem* code_item = verifier->CodeItem(); 95e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_NE(code_item->insns_size_in_code_units_, 0u); 96e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 97e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 98e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 99e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko switch (opcode) { 100e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_VOID: 1012c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (method != nullptr) { 1022c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz method->opcode = kInlineOpNop; 1032c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz method->flags = kInlineSpecial; 1042c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz method->d.data = 0u; 1052c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 106e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 107e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN: 108e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_OBJECT: 109e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_WIDE: 110e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseReturnMethod(code_item, method); 111e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST: 112e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_4: 113e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_16: 114e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_HIGH16: 115e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // TODO: Support wide constants (RETURN_WIDE). 116e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseConstMethod(code_item, method); 117e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET: 118e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_OBJECT: 119e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BOOLEAN: 120e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BYTE: 121e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_CHAR: 122e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_SHORT: 123e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_WIDE: 124e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseIGetMethod(verifier, method); 125e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT: 126e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_OBJECT: 127e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BOOLEAN: 128e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BYTE: 129e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_CHAR: 130e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_SHORT: 131e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_WIDE: 132e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseIPutMethod(verifier, method); 133e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko default: 134e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 135e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 136e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 137e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 138c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Markobool InlineMethodAnalyser::IsSyntheticAccessor(MethodReference ref) { 139c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko const DexFile::MethodId& method_id = ref.dex_file->GetMethodId(ref.dex_method_index); 140c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko const char* method_name = ref.dex_file->GetMethodName(method_id); 141c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko return strncmp(method_name, "access$", strlen("access$")) == 0; 142c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko} 143c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko 144e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item, 145e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 146e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = Instruction::At(code_item->insns_); 147e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 148e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t reg = return_instruction->VRegA_11x(); 149e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 150e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(reg, arg_start); 151e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg, 152e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 153e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 1542c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 1552c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpReturnArg; 1562c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 1572c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineReturnArgData* data = &result->d.return_data; 1582c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->arg = reg - arg_start; 1592c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u; 1602c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u; 1612c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->reserved = 0u; 1622c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->reserved2 = 0u; 1632c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 164e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 165e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 166e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 167e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item, 168e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 169e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 170e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 171e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 172e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN && 173e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return_opcode != Instruction::RETURN_OBJECT) { 174e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 175e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 176e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 17729a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers int32_t return_reg = return_instruction->VRegA_11x(); 178e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_reg, code_item->registers_size_); 179e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 18029a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers int32_t const_value = instruction->VRegB(); 181e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (instruction->Opcode() == Instruction::CONST_HIGH16) { 18229a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers const_value <<= 16; 183e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 18429a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers DCHECK_LT(instruction->VRegA(), code_item->registers_size_); 18529a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers if (instruction->VRegA() != return_reg) { 186e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value set by const? 187e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 18829a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers if (return_opcode == Instruction::RETURN_OBJECT && const_value != 0) { 189e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Returning non-null reference constant? 190e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 1912c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 1922c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpNonWideConst; 1932c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 19429a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers result->d.data = static_cast<uint64_t>(const_value); 1952c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 196e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 197e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 198e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 199e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseIGetMethod(verifier::MethodVerifier* verifier, 200e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 201e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const DexFile::CodeItem* code_item = verifier->CodeItem(); 202e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 203e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 204e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIGet(opcode)); 205e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 206e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 207e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 208e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!(return_opcode == Instruction::RETURN_WIDE && opcode == Instruction::IGET_WIDE) && 209e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT) && 210e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN && opcode != Instruction::IGET_WIDE && 211e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko opcode != Instruction::IGET_OBJECT)) { 212e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 213e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 214e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 215e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 216e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg, 217e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 218e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 219e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t dst_reg = instruction->VRegA_22c(); 220e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 221e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 222e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 223e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 224e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 225e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t object_arg = object_reg - arg_start; 226e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 227e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_); 228e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (dst_reg != return_reg) { 229e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value retrieved by IGET? 230e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 231e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 232e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if ((verifier->GetAccessFlags() & kAccStatic) != 0u || object_arg != 0u) { 233c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE). 234c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 235c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko if (!IsSyntheticAccessor(verifier->GetMethodReference())) { 236c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko return false; 237c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko } 238e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 239e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 240e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // InlineIGetIPutData::object_arg is only 4 bits wide. 241e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxObjectArg = 15u; 242e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (object_arg > kMaxObjectArg) { 243e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 244e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 245e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 2462c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 2472c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineIGetIPutData* data = &result->d.ifield_data; 2482c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (!ComputeSpecialAccessorInfo(field_idx, false, verifier, data)) { 2492c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz return false; 2502c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 2512c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpIGet; 2522c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 2532c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->op_variant = IGetVariant(opcode); 254c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0u ? 1u : 0u; 255e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->object_arg = object_arg; // Allow IGET on any register, not just "this". 256c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko data->src_arg = 0u; 257e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->return_arg_plus1 = 0u; 258e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 259e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 260e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 261e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 262e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseIPutMethod(verifier::MethodVerifier* verifier, 263e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 264e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const DexFile::CodeItem* code_item = verifier->CodeItem(); 265e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 266e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 267e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIPut(opcode)); 268e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 269e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 270e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 271e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 272e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint16_t return_arg_plus1 = 0u; 273e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN_VOID) { 274e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (return_opcode != Instruction::RETURN && 275e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_opcode != Instruction::RETURN_OBJECT && 276e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_opcode != Instruction::RETURN_WIDE) { 277e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 278e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 279e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // Returning an argument. 280e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 281e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko DCHECK_GE(return_reg, arg_start); 282e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg, 283e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko code_item->registers_size_); 284e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_arg_plus1 = return_reg - arg_start + 1u; 285e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 286e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 287e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t src_reg = instruction->VRegA_22c(); 288e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 289e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 290e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 291e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 292e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(src_reg, arg_start); 293e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_); 294e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t object_arg = object_reg - arg_start; 295e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t src_arg = src_reg - arg_start; 296e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 297c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko if ((verifier->GetAccessFlags() & kAccStatic) != 0u || object_arg != 0u) { 298c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE). 299c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 300c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko if (!IsSyntheticAccessor(verifier->GetMethodReference())) { 301c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko return false; 302c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko } 303e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 304e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 305e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // InlineIGetIPutData::object_arg/src_arg/return_arg_plus1 are each only 4 bits wide. 306e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxObjectArg = 15u; 307e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxSrcArg = 15u; 308e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxReturnArgPlus1 = 15u; 309e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (object_arg > kMaxObjectArg || src_arg > kMaxSrcArg || return_arg_plus1 > kMaxReturnArgPlus1) { 310e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 311e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 312e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 3132c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 3142c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineIGetIPutData* data = &result->d.ifield_data; 3152c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (!ComputeSpecialAccessorInfo(field_idx, true, verifier, data)) { 3162c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz return false; 3172c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 3182c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpIPut; 3192c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 3202c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->op_variant = IPutVariant(opcode); 321c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0u ? 1u : 0u; 322e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->object_arg = object_arg; // Allow IPUT on any register, not just "this". 323e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->src_arg = src_arg; 324e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->return_arg_plus1 = return_arg_plus1; 325e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 326e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 327e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 328e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 329e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put, 330e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko verifier::MethodVerifier* verifier, 331e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineIGetIPutData* result) { 332e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::DexCache* dex_cache = verifier->GetDexCache(); 333e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t method_idx = verifier->GetMethodReference().dex_method_index; 334e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx); 335e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::ArtField* field = dex_cache->GetResolvedField(field_idx); 336e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (method == nullptr || field == nullptr || field->IsStatic()) { 337e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 338e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 339e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::Class* method_class = method->GetDeclaringClass(); 340e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::Class* field_class = field->GetDeclaringClass(); 341e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) || 342e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko (is_put && field->IsFinal() && method_class != field_class)) { 343e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 344e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 345e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(field->GetOffset().Int32Value(), 0); 346e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->field_idx = field_idx; 347e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->field_offset = field->GetOffset().Int32Value(); 348e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->is_volatile = field->IsVolatile(); 349e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 350e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 351e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 352e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} // namespace art 353