1 /*
2  * Copyright (C) 2015 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_OPTIMIZING_INTRINSICS_H_
18 #define ART_COMPILER_OPTIMIZING_INTRINSICS_H_
19 
20 #include "code_generator.h"
21 #include "nodes.h"
22 #include "optimization.h"
23 #include "parallel_move_resolver.h"
24 
25 namespace art {
26 
27 class CompilerDriver;
28 class DexFile;
29 
30 // Positive floating-point infinities.
31 static constexpr uint32_t kPositiveInfinityFloat = 0x7f800000U;
32 static constexpr uint64_t kPositiveInfinityDouble = UINT64_C(0x7ff0000000000000);
33 
34 static constexpr uint32_t kNanFloat = 0x7fc00000U;
35 static constexpr uint64_t kNanDouble = 0x7ff8000000000000;
36 
37 // Recognize intrinsics from HInvoke nodes.
38 class IntrinsicsRecognizer : public HOptimization {
39  public:
40   IntrinsicsRecognizer(HGraph* graph,
41                        OptimizingCompilerStats* stats,
42                        const char* name = kIntrinsicsRecognizerPassName)
HOptimization(graph,name,stats)43       : HOptimization(graph, name, stats) {}
44 
45   void Run() OVERRIDE;
46 
47   // Static helper that recognizes intrinsic call. Returns true on success.
48   // If it fails due to invoke type mismatch, wrong_invoke_type is set.
49   // Useful to recognize intrinsics on individual calls outside this full pass.
50   static bool Recognize(HInvoke* invoke, ArtMethod* method, /*out*/ bool* wrong_invoke_type)
51       REQUIRES_SHARED(Locks::mutator_lock_);
52 
53   static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition";
54 
55  private:
56   DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer);
57 };
58 
59 class IntrinsicVisitor : public ValueObject {
60  public:
~IntrinsicVisitor()61   virtual ~IntrinsicVisitor() {}
62 
63   // Dispatch logic.
64 
Dispatch(HInvoke * invoke)65   void Dispatch(HInvoke* invoke) {
66     switch (invoke->GetIntrinsic()) {
67       case Intrinsics::kNone:
68         return;
69 #define OPTIMIZING_INTRINSICS(Name, ...) \
70       case Intrinsics::k ## Name: \
71         Visit ## Name(invoke);    \
72         return;
73 #include "intrinsics_list.h"
74         INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
75 #undef INTRINSICS_LIST
76 #undef OPTIMIZING_INTRINSICS
77 
78       // Do not put a default case. That way the compiler will complain if we missed a case.
79     }
80   }
81 
82   // Define visitor methods.
83 
84 #define OPTIMIZING_INTRINSICS(Name, ...) \
85   virtual void Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
86   }
87 #include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)88   INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
89 #undef INTRINSICS_LIST
90 #undef OPTIMIZING_INTRINSICS
91 
92   static void MoveArguments(HInvoke* invoke,
93                             CodeGenerator* codegen,
94                             InvokeDexCallingConventionVisitor* calling_convention_visitor) {
95     if (kIsDebugBuild && invoke->IsInvokeStaticOrDirect()) {
96       HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect();
97       // Explicit clinit checks triggered by static invokes must have been
98       // pruned by art::PrepareForRegisterAllocation.
99       DCHECK(!invoke_static_or_direct->IsStaticWithExplicitClinitCheck());
100     }
101 
102     if (invoke->GetNumberOfArguments() == 0) {
103       // No argument to move.
104       return;
105     }
106 
107     LocationSummary* locations = invoke->GetLocations();
108 
109     // We're moving potentially two or more locations to locations that could overlap, so we need
110     // a parallel move resolver.
111     HParallelMove parallel_move(codegen->GetGraph()->GetAllocator());
112 
113     for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) {
114       HInstruction* input = invoke->InputAt(i);
115       Location cc_loc = calling_convention_visitor->GetNextLocation(input->GetType());
116       Location actual_loc = locations->InAt(i);
117 
118       parallel_move.AddMove(actual_loc, cc_loc, input->GetType(), nullptr);
119     }
120 
121     codegen->GetMoveResolver()->EmitNativeCode(&parallel_move);
122   }
123 
124   static void ComputeIntegerValueOfLocations(HInvoke* invoke,
125                                              CodeGenerator* codegen,
126                                              Location return_location,
127                                              Location first_argument_location);
128 
129   // Temporary data structure for holding Integer.valueOf useful data. We only
130   // use it if the mirror::Class* are in the boot image, so it is fine to keep raw
131   // mirror::Class pointers in this structure.
132   struct IntegerValueOfInfo {
IntegerValueOfInfoIntegerValueOfInfo133     IntegerValueOfInfo()
134         : integer_cache(nullptr),
135           integer(nullptr),
136           cache(nullptr),
137           low(0),
138           high(0),
139           value_offset(0) {}
140 
141     // The java.lang.IntegerCache class.
142     mirror::Class* integer_cache;
143     // The java.lang.Integer class.
144     mirror::Class* integer;
145     // Value of java.lang.IntegerCache#cache.
146     mirror::ObjectArray<mirror::Object>* cache;
147     // Value of java.lang.IntegerCache#low.
148     int32_t low;
149     // Value of java.lang.IntegerCache#high.
150     int32_t high;
151     // The offset of java.lang.Integer.value.
152     int32_t value_offset;
153   };
154 
155   static IntegerValueOfInfo ComputeIntegerValueOfInfo();
156 
157  protected:
IntrinsicVisitor()158   IntrinsicVisitor() {}
159 
160  private:
161   DISALLOW_COPY_AND_ASSIGN(IntrinsicVisitor);
162 };
163 
164 #define GENERIC_OPTIMIZATION(name, bit)                \
165 public:                                                \
166 void Set##name() { SetBit(k##name); }                  \
167 bool Get##name() const { return IsBitSet(k##name); }   \
168 private:                                               \
169 static constexpr size_t k##name = bit
170 
171 class IntrinsicOptimizations : public ValueObject {
172  public:
IntrinsicOptimizations(HInvoke * invoke)173   explicit IntrinsicOptimizations(HInvoke* invoke)
174       : value_(invoke->GetIntrinsicOptimizations()) {}
IntrinsicOptimizations(const HInvoke & invoke)175   explicit IntrinsicOptimizations(const HInvoke& invoke)
176       : value_(invoke.GetIntrinsicOptimizations()) {}
177 
178   static constexpr int kNumberOfGenericOptimizations = 2;
179   GENERIC_OPTIMIZATION(DoesNotNeedDexCache, 0);
180   GENERIC_OPTIMIZATION(DoesNotNeedEnvironment, 1);
181 
182  protected:
IsBitSet(uint32_t bit)183   bool IsBitSet(uint32_t bit) const {
184     DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte);
185     return (*value_ & (1 << bit)) != 0u;
186   }
187 
SetBit(uint32_t bit)188   void SetBit(uint32_t bit) {
189     DCHECK_LT(bit, sizeof(uint32_t) * kBitsPerByte);
190     *(const_cast<uint32_t* const>(value_)) |= (1 << bit);
191   }
192 
193  private:
194   const uint32_t* const value_;
195 
196   DISALLOW_COPY_AND_ASSIGN(IntrinsicOptimizations);
197 };
198 
199 #undef GENERIC_OPTIMIZATION
200 
201 #define INTRINSIC_OPTIMIZATION(name, bit)                             \
202 public:                                                               \
203 void Set##name() { SetBit(k##name); }                                 \
204 bool Get##name() const { return IsBitSet(k##name); }                  \
205 private:                                                              \
206 static constexpr size_t k##name = (bit) + kNumberOfGenericOptimizations
207 
208 class StringEqualsOptimizations : public IntrinsicOptimizations {
209  public:
StringEqualsOptimizations(HInvoke * invoke)210   explicit StringEqualsOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
211 
212   INTRINSIC_OPTIMIZATION(ArgumentNotNull, 0);
213   INTRINSIC_OPTIMIZATION(ArgumentIsString, 1);
214   INTRINSIC_OPTIMIZATION(NoReadBarrierForStringClass, 2);
215 
216  private:
217   DISALLOW_COPY_AND_ASSIGN(StringEqualsOptimizations);
218 };
219 
220 class SystemArrayCopyOptimizations : public IntrinsicOptimizations {
221  public:
SystemArrayCopyOptimizations(HInvoke * invoke)222   explicit SystemArrayCopyOptimizations(HInvoke* invoke) : IntrinsicOptimizations(invoke) {}
223 
224   INTRINSIC_OPTIMIZATION(SourceIsNotNull, 0);
225   INTRINSIC_OPTIMIZATION(DestinationIsNotNull, 1);
226   INTRINSIC_OPTIMIZATION(DestinationIsSource, 2);
227   INTRINSIC_OPTIMIZATION(CountIsSourceLength, 3);
228   INTRINSIC_OPTIMIZATION(CountIsDestinationLength, 4);
229   INTRINSIC_OPTIMIZATION(DoesNotNeedTypeCheck, 5);
230   INTRINSIC_OPTIMIZATION(DestinationIsTypedObjectArray, 6);
231   INTRINSIC_OPTIMIZATION(DestinationIsNonPrimitiveArray, 7);
232   INTRINSIC_OPTIMIZATION(DestinationIsPrimitiveArray, 8);
233   INTRINSIC_OPTIMIZATION(SourceIsNonPrimitiveArray, 9);
234   INTRINSIC_OPTIMIZATION(SourceIsPrimitiveArray, 10);
235 
236  private:
237   DISALLOW_COPY_AND_ASSIGN(SystemArrayCopyOptimizations);
238 };
239 
240 #undef INTRISIC_OPTIMIZATION
241 
242 //
243 // Macros for use in the intrinsics code generators.
244 //
245 
246 // Defines an unimplemented intrinsic: that is, a method call that is recognized as an
247 // intrinsic to exploit e.g. no side-effects or exceptions, but otherwise not handled
248 // by this architecture-specific intrinsics code generator. Eventually it is implemented
249 // as a true method call.
250 #define UNIMPLEMENTED_INTRINSIC(Arch, Name)                                               \
251 void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
252 }                                                                                         \
253 void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) {    \
254 }
255 
256 // Defines a list of unreached intrinsics: that is, method calls that are recognized as
257 // an intrinsic, and then always converted into HIR instructions before they reach any
258 // architecture-specific intrinsics code generator.
259 #define UNREACHABLE_INTRINSIC(Arch, Name)                                \
260 void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke) { \
261   LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic()      \
262              << " should have been converted to HIR";                    \
263 }                                                                        \
264 void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke) {    \
265   LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic()      \
266              << " should have been converted to HIR";                    \
267 }
268 #define UNREACHABLE_INTRINSICS(Arch)                            \
269 UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits)                \
270 UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits)             \
271 UNREACHABLE_INTRINSIC(Arch, FloatIsNaN)                         \
272 UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN)                        \
273 UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft)                  \
274 UNREACHABLE_INTRINSIC(Arch, LongRotateLeft)                     \
275 UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight)                 \
276 UNREACHABLE_INTRINSIC(Arch, LongRotateRight)                    \
277 UNREACHABLE_INTRINSIC(Arch, IntegerCompare)                     \
278 UNREACHABLE_INTRINSIC(Arch, LongCompare)                        \
279 UNREACHABLE_INTRINSIC(Arch, IntegerSignum)                      \
280 UNREACHABLE_INTRINSIC(Arch, LongSignum)                         \
281 UNREACHABLE_INTRINSIC(Arch, StringCharAt)                       \
282 UNREACHABLE_INTRINSIC(Arch, StringIsEmpty)                      \
283 UNREACHABLE_INTRINSIC(Arch, StringLength)                       \
284 UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence)                    \
285 UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence)                   \
286 UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence)                    \
287 UNREACHABLE_INTRINSIC(Arch, VarHandleFullFence)                 \
288 UNREACHABLE_INTRINSIC(Arch, VarHandleAcquireFence)              \
289 UNREACHABLE_INTRINSIC(Arch, VarHandleReleaseFence)              \
290 UNREACHABLE_INTRINSIC(Arch, VarHandleLoadLoadFence)             \
291 UNREACHABLE_INTRINSIC(Arch, VarHandleStoreStoreFence)           \
292 UNREACHABLE_INTRINSIC(Arch, MethodHandleInvokeExact)            \
293 UNREACHABLE_INTRINSIC(Arch, MethodHandleInvoke)                 \
294 UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndExchange)        \
295 UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndExchangeAcquire) \
296 UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndExchangeRelease) \
297 UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndSet)             \
298 UNREACHABLE_INTRINSIC(Arch, VarHandleGet)                       \
299 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAcquire)                \
300 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndAdd)                 \
301 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndAddAcquire)          \
302 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndAddRelease)          \
303 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseAnd)          \
304 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseAndAcquire)   \
305 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseAndRelease)   \
306 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseOr)           \
307 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseOrAcquire)    \
308 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseOrRelease)    \
309 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseXor)          \
310 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseXorAcquire)   \
311 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseXorRelease)   \
312 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndSet)                 \
313 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndSetAcquire)          \
314 UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndSetRelease)          \
315 UNREACHABLE_INTRINSIC(Arch, VarHandleGetOpaque)                 \
316 UNREACHABLE_INTRINSIC(Arch, VarHandleGetVolatile)               \
317 UNREACHABLE_INTRINSIC(Arch, VarHandleSet)                       \
318 UNREACHABLE_INTRINSIC(Arch, VarHandleSetOpaque)                 \
319 UNREACHABLE_INTRINSIC(Arch, VarHandleSetRelease)                \
320 UNREACHABLE_INTRINSIC(Arch, VarHandleSetVolatile)               \
321 UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSet)         \
322 UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSetAcquire)  \
323 UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSetPlain)    \
324 UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSetRelease)
325 
326 template <typename IntrinsicLocationsBuilder, typename Codegenerator>
IsCallFreeIntrinsic(HInvoke * invoke,Codegenerator * codegen)327 bool IsCallFreeIntrinsic(HInvoke* invoke, Codegenerator* codegen) {
328   if (invoke->GetIntrinsic() != Intrinsics::kNone) {
329     // This invoke may have intrinsic code generation defined. However, we must
330     // now also determine if this code generation is truly there and call-free
331     // (not unimplemented, no bail on instruction features, or call on slow path).
332     // This is done by actually calling the locations builder on the instruction
333     // and clearing out the locations once result is known. We assume this
334     // call only has creating locations as side effects!
335     // TODO: Avoid wasting Arena memory.
336     IntrinsicLocationsBuilder builder(codegen);
337     bool success = builder.TryDispatch(invoke) && !invoke->GetLocations()->CanCall();
338     invoke->SetLocations(nullptr);
339     return success;
340   }
341   return false;
342 }
343 
344 }  // namespace art
345 
346 #endif  // ART_COMPILER_OPTIMIZING_INTRINSICS_H_
347