inline_method_analyser.cc revision d5f1005da7599f149b1332402c9791ef2acb8c42
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" 203481ba2c4e4f3aa80d8c6d50a9f85dacb56b508bVladimir Marko#include "class_linker-inl.h" 21956af0f0cb05422e38c1d22cbef309d16b8a1a12Elliott Hughes#include "dex_file-inl.h" 22e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "dex_instruction.h" 23e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "dex_instruction-inl.h" 24e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/art_method-inl.h" 25e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/class-inl.h" 26e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "mirror/dex_cache-inl.h" 27e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko#include "verifier/method_verifier-inl.h" 28e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 29e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko/* 30e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * NOTE: This code is part of the quick compiler. It lives in the runtime 31e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko * only to allow the debugger to check whether a method has been inlined. 32e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko */ 33e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 34e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markonamespace art { 35e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 36575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET), "iget type"); 37575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_WIDE), "iget_wide type"); 38575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_OBJECT), 39575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe "iget_object type"); 40575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BOOLEAN), 41575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe "iget_boolean type"); 42575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_BYTE), "iget_byte type"); 43575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_CHAR), "iget_char type"); 44575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_SHORT), "iget_short type"); 45575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT), "iput type"); 46575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_WIDE), "iput_wide type"); 47575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_OBJECT), 48575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe "iput_object type"); 49575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BOOLEAN), 50575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe "iput_boolean type"); 51575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_BYTE), "iput_byte type"); 52575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_CHAR), "iput_char type"); 53575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IsInstructionIPut(Instruction::IPUT_SHORT), "iput_short type"); 54575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET) == 55575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT), "iget/iput variant"); 56575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_WIDE) == 57575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_WIDE), "iget/iput_wide variant"); 58575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_OBJECT) == 59575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_OBJECT), "iget/iput_object variant"); 60575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BOOLEAN) == 61575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BOOLEAN), "iget/iput_boolean variant"); 62575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_BYTE) == 63575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_BYTE), "iget/iput_byte variant"); 64575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_CHAR) == 65575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_CHAR), "iget/iput_char variant"); 66575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampestatic_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) == 67575e78c41ece0dec969d31f46be563d4eb7ae43bAndreas Gampe InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant"); 68e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 692c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// This is used by compiler and debugger. We look into the dex cache for resolved methods and 702c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// fields. However, in the context of the debugger, not all methods and fields are resolved. Since 712c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// we need to be able to detect possibly inlined method, we pass a null inline method to indicate 722c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz// we don't want to take unresolved methods and fields into account during analysis. 73e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseMethodCode(verifier::MethodVerifier* verifier, 74e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* method) { 752c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz DCHECK(verifier != nullptr); 762c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz DCHECK_EQ(Runtime::Current()->IsCompiler(), method != nullptr); 77e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier if (!Runtime::Current()->UseJit()) { 78e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier DCHECK_EQ(verifier->CanLoadClasses(), method != nullptr); 79e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier } 80e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // We currently support only plain return or 2-instruction methods. 81e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 82e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const DexFile::CodeItem* code_item = verifier->CodeItem(); 83e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_NE(code_item->insns_size_in_code_units_, 0u); 84e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 85e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 86e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 87e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko switch (opcode) { 88e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_VOID: 892c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (method != nullptr) { 902c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz method->opcode = kInlineOpNop; 912c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz method->flags = kInlineSpecial; 922c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz method->d.data = 0u; 932c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 94e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 95e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN: 96e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_OBJECT: 97e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::RETURN_WIDE: 98e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseReturnMethod(code_item, method); 99e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST: 100e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_4: 101e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_16: 102e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::CONST_HIGH16: 103e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko // TODO: Support wide constants (RETURN_WIDE). 104e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseConstMethod(code_item, method); 105e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET: 106e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_OBJECT: 107e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BOOLEAN: 108e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_BYTE: 109e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_CHAR: 110e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_SHORT: 111e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IGET_WIDE: 112e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // TODO: Add handling for JIT. 113e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IGET_QUICK: 114e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IGET_WIDE_QUICK: 115e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IGET_OBJECT_QUICK: 116e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseIGetMethod(verifier, method); 117e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT: 118e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_OBJECT: 119e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BOOLEAN: 120e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_BYTE: 121e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_CHAR: 122e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_SHORT: 123e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko case Instruction::IPUT_WIDE: 124e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // TODO: Add handling for JIT. 125e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IPUT_QUICK: 126e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IPUT_WIDE_QUICK: 127e5f13e57ff8fa36342beb33830b3ec5942a61ccaMathieu Chartier // case Instruction::IPUT_OBJECT_QUICK: 128e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return AnalyseIPutMethod(verifier, method); 129e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko default: 130e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 131e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 132e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 133e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 134c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Markobool InlineMethodAnalyser::IsSyntheticAccessor(MethodReference ref) { 135c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko const DexFile::MethodId& method_id = ref.dex_file->GetMethodId(ref.dex_method_index); 136c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko const char* method_name = ref.dex_file->GetMethodName(method_id); 137d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko // javac names synthetic accessors "access$nnn", 138d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko // jack names them "-getN", "-putN", "-wrapN". 139d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko return strncmp(method_name, "access$", strlen("access$")) == 0 || 140d5f1005da7599f149b1332402c9791ef2acb8c42Vladimir Marko strncmp(method_name, "-", strlen("-")) == 0; 141c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko} 142c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko 143e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item, 144e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 145e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = Instruction::At(code_item->insns_); 146e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 147e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t reg = return_instruction->VRegA_11x(); 148e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 149e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(reg, arg_start); 150e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg, 151e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 152e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 1532c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 1542c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpReturnArg; 1552c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 1562c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineReturnArgData* data = &result->d.return_data; 1572c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->arg = reg - arg_start; 1582c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->is_wide = (return_opcode == Instruction::RETURN_WIDE) ? 1u : 0u; 1592c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->is_object = (return_opcode == Instruction::RETURN_OBJECT) ? 1u : 0u; 1602c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->reserved = 0u; 1612c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->reserved2 = 0u; 1622c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 163e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 164e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 165e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 166e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item, 167e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 168e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 169e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 170e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 171e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN && 172e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return_opcode != Instruction::RETURN_OBJECT) { 173e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 174e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 175e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 17629a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers int32_t return_reg = return_instruction->VRegA_11x(); 177e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_reg, code_item->registers_size_); 178e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 17929a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers int32_t const_value = instruction->VRegB(); 180e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (instruction->Opcode() == Instruction::CONST_HIGH16) { 18129a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers const_value <<= 16; 182e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 18329a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers DCHECK_LT(instruction->VRegA(), code_item->registers_size_); 18429a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers if (instruction->VRegA() != return_reg) { 185e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value set by const? 186e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 18729a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers if (return_opcode == Instruction::RETURN_OBJECT && const_value != 0) { 188e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Returning non-null reference constant? 189e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 1902c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 1912c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpNonWideConst; 1922c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 19329a2648821ea4d0b5d3aecb9f835822fdfe6faa1Ian Rogers result->d.data = static_cast<uint64_t>(const_value); 1942c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 195e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 196e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 197e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 198e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseIGetMethod(verifier::MethodVerifier* verifier, 199e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 200e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const DexFile::CodeItem* code_item = verifier->CodeItem(); 201e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 202e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 203e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIGet(opcode)); 204e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 205e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 206e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 207e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!(return_opcode == Instruction::RETURN_WIDE && opcode == Instruction::IGET_WIDE) && 208e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN_OBJECT && opcode == Instruction::IGET_OBJECT) && 209e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko !(return_opcode == Instruction::RETURN && opcode != Instruction::IGET_WIDE && 210e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko opcode != Instruction::IGET_OBJECT)) { 211e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 212e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 213e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 214e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 215e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg, 216e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko code_item->registers_size_); 217e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 218e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t dst_reg = instruction->VRegA_22c(); 219e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 220e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 221e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 222e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 223e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 224e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t object_arg = object_reg - arg_start; 225e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 226e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_); 227e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (dst_reg != return_reg) { 228e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; // Not returning the value retrieved by IGET? 229e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 230e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 231e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if ((verifier->GetAccessFlags() & kAccStatic) != 0u || object_arg != 0u) { 232c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // TODO: Implement inlining of IGET on non-"this" registers (needs correct stack trace for NPE). 233c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 234c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko if (!IsSyntheticAccessor(verifier->GetMethodReference())) { 235c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko return false; 236c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko } 237e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 238e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 239e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // InlineIGetIPutData::object_arg is only 4 bits wide. 240e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxObjectArg = 15u; 241e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (object_arg > kMaxObjectArg) { 242e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 243e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 244e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 2452c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 2462c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineIGetIPutData* data = &result->d.ifield_data; 2472c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (!ComputeSpecialAccessorInfo(field_idx, false, verifier, data)) { 2482c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz return false; 2492c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 2502c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpIGet; 2512c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 2522c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->op_variant = IGetVariant(opcode); 253c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0u ? 1u : 0u; 254e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->object_arg = object_arg; // Allow IGET on any register, not just "this". 255c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko data->src_arg = 0u; 256e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->return_arg_plus1 = 0u; 257e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 258e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 259e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 260e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 261e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::AnalyseIPutMethod(verifier::MethodVerifier* verifier, 262e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineMethod* result) { 263e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const DexFile::CodeItem* code_item = verifier->CodeItem(); 264e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* instruction = Instruction::At(code_item->insns_); 265e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code opcode = instruction->Opcode(); 266e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK(IsInstructionIPut(opcode)); 267e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 268e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko const Instruction* return_instruction = instruction->Next(); 269e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko Instruction::Code return_opcode = return_instruction->Opcode(); 270e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; 271e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint16_t return_arg_plus1 = 0u; 272e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (return_opcode != Instruction::RETURN_VOID) { 273e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (return_opcode != Instruction::RETURN && 274e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_opcode != Instruction::RETURN_OBJECT && 275e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_opcode != Instruction::RETURN_WIDE) { 276e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 277e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 278e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // Returning an argument. 279e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t return_reg = return_instruction->VRegA_11x(); 280e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko DCHECK_GE(return_reg, arg_start); 281e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg, 282e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko code_item->registers_size_); 283e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return_arg_plus1 = return_reg - arg_start + 1u; 284e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 285e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 286e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t src_reg = instruction->VRegA_22c(); 287e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t object_reg = instruction->VRegB_22c(); 288e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t field_idx = instruction->VRegC_22c(); 289e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(object_reg, arg_start); 290e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(object_reg, code_item->registers_size_); 291e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(src_reg, arg_start); 292e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_); 293e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t object_arg = object_reg - arg_start; 294e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko uint32_t src_arg = src_reg - arg_start; 295e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 296c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko if ((verifier->GetAccessFlags() & kAccStatic) != 0u || object_arg != 0u) { 297c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // TODO: Implement inlining of IPUT on non-"this" registers (needs correct stack trace for NPE). 298c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko // Allow synthetic accessors. We don't care about losing their stack frame in NPE. 299c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko if (!IsSyntheticAccessor(verifier->GetMethodReference())) { 300c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko return false; 301c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko } 302e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 303e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 304e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko // InlineIGetIPutData::object_arg/src_arg/return_arg_plus1 are each only 4 bits wide. 305e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxObjectArg = 15u; 306e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxSrcArg = 15u; 307e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko static constexpr uint16_t kMaxReturnArgPlus1 = 15u; 308e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko if (object_arg > kMaxObjectArg || src_arg > kMaxSrcArg || return_arg_plus1 > kMaxReturnArgPlus1) { 309e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko return false; 310e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko } 311e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko 3122c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (result != nullptr) { 3132c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz InlineIGetIPutData* data = &result->d.ifield_data; 3142c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz if (!ComputeSpecialAccessorInfo(field_idx, true, verifier, data)) { 3152c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz return false; 3162c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz } 3172c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->opcode = kInlineOpIPut; 3182c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz result->flags = kInlineSpecial; 3192c87c4d999bccdff6cc60bf6af4871cca6e2c893Sebastien Hertz data->op_variant = IPutVariant(opcode); 320c8f60a69a9f2420fc1ecafec612a667be8dcd547Vladimir Marko data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0u ? 1u : 0u; 321e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->object_arg = object_arg; // Allow IPUT on any register, not just "this". 322e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->src_arg = src_arg; 323e1fced1d1805caec04b6e97d2b01a4977c6785c6Vladimir Marko data->return_arg_plus1 = return_arg_plus1; 324e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 325e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 326e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 327e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 328e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Markobool InlineMethodAnalyser::ComputeSpecialAccessorInfo(uint32_t field_idx, bool is_put, 329e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko verifier::MethodVerifier* verifier, 330e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko InlineIGetIPutData* result) { 331e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::DexCache* dex_cache = verifier->GetDexCache(); 332e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko uint32_t method_idx = verifier->GetMethodReference().dex_method_index; 333e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx); 334c785344b87221f5e4e6473e5b762e4e61fe65dcfMathieu Chartier ArtField* field = Runtime::Current()->GetClassLinker()->GetResolvedField(field_idx, dex_cache); 335e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (method == nullptr || field == nullptr || field->IsStatic()) { 336e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 337e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 338e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::Class* method_class = method->GetDeclaringClass(); 339e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko mirror::Class* field_class = field->GetDeclaringClass(); 340e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko if (!method_class->CanAccessResolvedField(field_class, field, dex_cache, field_idx) || 341e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko (is_put && field->IsFinal() && method_class != field_class)) { 342e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return false; 343e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko } 344e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko DCHECK_GE(field->GetOffset().Int32Value(), 0); 345e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->field_idx = field_idx; 346e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->field_offset = field->GetOffset().Int32Value(); 347e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko result->is_volatile = field->IsVolatile(); 348e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko return true; 349e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} 350e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko 351e3e0260c23d8999b9433715ac7ee5296ee2fd633Vladimir Marko} // namespace art 352