1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_COMPILER_DEX_INLINE_METHOD_ANALYSER_H_
18 #define ART_COMPILER_DEX_INLINE_METHOD_ANALYSER_H_
19 
20 #include "base/macros.h"
21 #include "base/mutex.h"
22 #include "dex/dex_file.h"
23 #include "dex/dex_instruction.h"
24 
25 /*
26  * NOTE: This code is part of the quick compiler. It lives in the runtime
27  * only to allow the debugger to check whether a method has been inlined.
28  */
29 
30 namespace art HIDDEN {
31 
32 class CodeItemDataAccessor;
33 
34 namespace verifier {
35 class MethodVerifier;
36 }  // namespace verifier
37 class ArtMethod;
38 
39 enum InlineMethodOpcode : uint16_t {
40   kInlineOpNop,
41   kInlineOpReturnArg,
42   kInlineOpNonWideConst,
43   kInlineOpIGet,
44   kInlineOpIPut,
45   kInlineOpConstructor,
46 };
47 
48 struct InlineIGetIPutData {
49   // The op_variant below is DexMemAccessType but the runtime doesn't know that enumeration.
50   uint16_t op_variant : 3;
51   uint16_t method_is_static : 1;
52   uint16_t object_arg : 4;
53   uint16_t src_arg : 4;  // iput only
54   uint16_t return_arg_plus1 : 4;  // iput only, method argument to return + 1, 0 = return void.
55   uint16_t field_idx;
56   uint32_t is_volatile : 1;
57   uint32_t field_offset : 31;
58 };
59 static_assert(sizeof(InlineIGetIPutData) == sizeof(uint64_t), "Invalid size of InlineIGetIPutData");
60 
61 struct InlineReturnArgData {
62   uint16_t arg;
63   uint16_t is_wide : 1;
64   uint16_t is_object : 1;
65   uint16_t reserved : 14;
66   uint32_t reserved2;
67 };
68 static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
69               "Invalid size of InlineReturnArgData");
70 
71 struct InlineConstructorData {
72   // There can be up to 3 IPUTs, unused fields are marked with kNoDexIndex16.
73   uint16_t iput0_field_index;
74   uint16_t iput1_field_index;
75   uint16_t iput2_field_index;
76   uint16_t iput0_arg : 4;
77   uint16_t iput1_arg : 4;
78   uint16_t iput2_arg : 4;
79   uint16_t reserved : 4;
80 };
81 static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t),
82               "Invalid size of InlineConstructorData");
83 
84 struct InlineMethod {
85   InlineMethodOpcode opcode;
86   union {
87     uint64_t data;
88     InlineIGetIPutData ifield_data;
89     InlineReturnArgData return_data;
90     InlineConstructorData constructor_data;
91   } d;
92 };
93 
94 class InlineMethodAnalyser {
95  public:
96   /**
97    * Analyse method code to determine if the method is a candidate for inlining.
98    * If it is, record the inlining data.
99    *
100    * @return true if the method is a candidate for inlining, false otherwise.
101    */
102   static bool AnalyseMethodCode(ArtMethod* method,
103                                 const CodeItemDataAccessor* code_item,
104                                 InlineMethod* result)
105       REQUIRES_SHARED(Locks::mutator_lock_);
106 
107   // Determines whether the method is a synthetic accessor (method name starts with "access$").
108   static bool IsSyntheticAccessor(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
109 
110  private:
111   static bool AnalyseReturnMethod(const CodeItemDataAccessor* code_item, InlineMethod* result);
112   static bool AnalyseConstMethod(const CodeItemDataAccessor* code_item, InlineMethod* result);
113   static bool AnalyseIGetMethod(ArtMethod* method,
114                                 const CodeItemDataAccessor* code_item,
115                                 InlineMethod* result)
116       REQUIRES_SHARED(Locks::mutator_lock_);
117   static bool AnalyseIPutMethod(ArtMethod* method,
118                                 const CodeItemDataAccessor* code_item,
119                                 InlineMethod* result)
120       REQUIRES_SHARED(Locks::mutator_lock_);
121 
122   // Can we fast path instance field access in a verified accessor?
123   // If yes, computes field's offset and volatility and whether the method is static or not.
124   static bool ComputeSpecialAccessorInfo(ArtMethod* method,
125                                          uint32_t field_idx,
126                                          bool is_put,
127                                          InlineIGetIPutData* result)
128       REQUIRES_SHARED(Locks::mutator_lock_);
129 };
130 
131 }  // namespace art
132 
133 #endif  // ART_COMPILER_DEX_INLINE_METHOD_ANALYSER_H_
134