xref: /aosp_15_r20/art/compiler/optimizing/intrinsics.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "intrinsics.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "art_field-inl.h"
20*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/utils.h"
22*795d594fSAndroid Build Coastguard Worker #include "class_linker.h"
23*795d594fSAndroid Build Coastguard Worker #include "class_root-inl.h"
24*795d594fSAndroid Build Coastguard Worker #include "code_generator.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex/invoke_type.h"
26*795d594fSAndroid Build Coastguard Worker #include "driver/compiler_options.h"
27*795d594fSAndroid Build Coastguard Worker #include "gc/space/image_space.h"
28*795d594fSAndroid Build Coastguard Worker #include "intrinsic_objects.h"
29*795d594fSAndroid Build Coastguard Worker #include "intrinsics_list.h"
30*795d594fSAndroid Build Coastguard Worker #include "nodes.h"
31*795d594fSAndroid Build Coastguard Worker #include "oat/image-inl.h"
32*795d594fSAndroid Build Coastguard Worker #include "obj_ptr-inl.h"
33*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
34*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
35*795d594fSAndroid Build Coastguard Worker #include "well_known_classes-inl.h"
36*795d594fSAndroid Build Coastguard Worker 
37*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
38*795d594fSAndroid Build Coastguard Worker 
operator <<(std::ostream & os,const Intrinsics & intrinsic)39*795d594fSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic) {
40*795d594fSAndroid Build Coastguard Worker   switch (intrinsic) {
41*795d594fSAndroid Build Coastguard Worker     case Intrinsics::kNone:
42*795d594fSAndroid Build Coastguard Worker       os << "None";
43*795d594fSAndroid Build Coastguard Worker       break;
44*795d594fSAndroid Build Coastguard Worker #define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
45*795d594fSAndroid Build Coastguard Worker     case Intrinsics::k ## Name: \
46*795d594fSAndroid Build Coastguard Worker       os << # Name; \
47*795d594fSAndroid Build Coastguard Worker       break;
48*795d594fSAndroid Build Coastguard Worker       ART_INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
49*795d594fSAndroid Build Coastguard Worker #undef OPTIMIZING_INTRINSICS
50*795d594fSAndroid Build Coastguard Worker   }
51*795d594fSAndroid Build Coastguard Worker   return os;
52*795d594fSAndroid Build Coastguard Worker }
53*795d594fSAndroid Build Coastguard Worker 
GetBootImageLiveObjects()54*795d594fSAndroid Build Coastguard Worker static ObjPtr<mirror::ObjectArray<mirror::Object>> GetBootImageLiveObjects()
55*795d594fSAndroid Build Coastguard Worker     REQUIRES_SHARED(Locks::mutator_lock_) {
56*795d594fSAndroid Build Coastguard Worker   gc::Heap* heap = Runtime::Current()->GetHeap();
57*795d594fSAndroid Build Coastguard Worker   const std::vector<gc::space::ImageSpace*>& boot_image_spaces = heap->GetBootImageSpaces();
58*795d594fSAndroid Build Coastguard Worker   DCHECK(!boot_image_spaces.empty());
59*795d594fSAndroid Build Coastguard Worker   const ImageHeader& main_header = boot_image_spaces[0]->GetImageHeader();
60*795d594fSAndroid Build Coastguard Worker   ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects =
61*795d594fSAndroid Build Coastguard Worker       ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast(
62*795d594fSAndroid Build Coastguard Worker           main_header.GetImageRoot<kWithoutReadBarrier>(ImageHeader::kBootImageLiveObjects));
63*795d594fSAndroid Build Coastguard Worker   DCHECK(boot_image_live_objects != nullptr);
64*795d594fSAndroid Build Coastguard Worker   DCHECK(heap->ObjectIsInBootImageSpace(boot_image_live_objects));
65*795d594fSAndroid Build Coastguard Worker   return boot_image_live_objects;
66*795d594fSAndroid Build Coastguard Worker }
67*795d594fSAndroid Build Coastguard Worker 
CanReferenceBootImageObjects(HInvoke * invoke,const CompilerOptions & compiler_options)68*795d594fSAndroid Build Coastguard Worker static bool CanReferenceBootImageObjects(HInvoke* invoke, const CompilerOptions& compiler_options) {
69*795d594fSAndroid Build Coastguard Worker   // Piggyback on the method load kind to determine whether we can use PC-relative addressing
70*795d594fSAndroid Build Coastguard Worker   // for AOT. This should cover both the testing config (non-PIC boot image) and codegens that
71*795d594fSAndroid Build Coastguard Worker   // reject PC-relative load kinds and fall back to the runtime call.
72*795d594fSAndroid Build Coastguard Worker   if (compiler_options.IsAotCompiler() &&
73*795d594fSAndroid Build Coastguard Worker       !invoke->AsInvokeStaticOrDirect()->HasPcRelativeMethodLoadKind()) {
74*795d594fSAndroid Build Coastguard Worker     return false;
75*795d594fSAndroid Build Coastguard Worker   }
76*795d594fSAndroid Build Coastguard Worker   if (!compiler_options.IsBootImage() &&
77*795d594fSAndroid Build Coastguard Worker       Runtime::Current()->GetHeap()->GetBootImageSpaces().empty()) {
78*795d594fSAndroid Build Coastguard Worker     return false;  // Running without boot image, cannot use required boot image objects.
79*795d594fSAndroid Build Coastguard Worker   }
80*795d594fSAndroid Build Coastguard Worker   return true;
81*795d594fSAndroid Build Coastguard Worker }
82*795d594fSAndroid Build Coastguard Worker 
ComputeValueOfLocations(HInvoke * invoke,CodeGenerator * codegen,int32_t low,int32_t length,Location return_location,Location first_argument_location)83*795d594fSAndroid Build Coastguard Worker void IntrinsicVisitor::ComputeValueOfLocations(HInvoke* invoke,
84*795d594fSAndroid Build Coastguard Worker                                                CodeGenerator* codegen,
85*795d594fSAndroid Build Coastguard Worker                                                int32_t low,
86*795d594fSAndroid Build Coastguard Worker                                                int32_t length,
87*795d594fSAndroid Build Coastguard Worker                                                Location return_location,
88*795d594fSAndroid Build Coastguard Worker                                                Location first_argument_location) {
89*795d594fSAndroid Build Coastguard Worker   // The intrinsic will call if it needs to allocate a boxed object.
90*795d594fSAndroid Build Coastguard Worker   LocationSummary::CallKind call_kind = LocationSummary::kCallOnMainOnly;
91*795d594fSAndroid Build Coastguard Worker   const CompilerOptions& compiler_options = codegen->GetCompilerOptions();
92*795d594fSAndroid Build Coastguard Worker   if (!CanReferenceBootImageObjects(invoke, compiler_options)) {
93*795d594fSAndroid Build Coastguard Worker     return;
94*795d594fSAndroid Build Coastguard Worker   }
95*795d594fSAndroid Build Coastguard Worker   HInstruction* const input = invoke->InputAt(0);
96*795d594fSAndroid Build Coastguard Worker   if (input->IsIntConstant()) {
97*795d594fSAndroid Build Coastguard Worker     int32_t value = input->AsIntConstant()->GetValue();
98*795d594fSAndroid Build Coastguard Worker     if (static_cast<uint32_t>(value) - static_cast<uint32_t>(low) < static_cast<uint32_t>(length)) {
99*795d594fSAndroid Build Coastguard Worker       // No call, we shall use direct pointer to the boxed object.
100*795d594fSAndroid Build Coastguard Worker       call_kind = LocationSummary::kNoCall;
101*795d594fSAndroid Build Coastguard Worker     }
102*795d594fSAndroid Build Coastguard Worker   }
103*795d594fSAndroid Build Coastguard Worker 
104*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = codegen->GetGraph()->GetAllocator();
105*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations = new (allocator) LocationSummary(invoke, call_kind, kIntrinsified);
106*795d594fSAndroid Build Coastguard Worker   if (call_kind == LocationSummary::kCallOnMainOnly) {
107*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::RegisterOrConstant(input));
108*795d594fSAndroid Build Coastguard Worker     locations->AddTemp(first_argument_location);
109*795d594fSAndroid Build Coastguard Worker     locations->SetOut(return_location);
110*795d594fSAndroid Build Coastguard Worker   } else {
111*795d594fSAndroid Build Coastguard Worker     locations->SetInAt(0, Location::ConstantLocation(input));
112*795d594fSAndroid Build Coastguard Worker     locations->SetOut(Location::RequiresRegister());
113*795d594fSAndroid Build Coastguard Worker   }
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker 
ValueOfInfo()116*795d594fSAndroid Build Coastguard Worker inline IntrinsicVisitor::ValueOfInfo::ValueOfInfo()
117*795d594fSAndroid Build Coastguard Worker     : value_offset(0),
118*795d594fSAndroid Build Coastguard Worker       low(0),
119*795d594fSAndroid Build Coastguard Worker       length(0u),
120*795d594fSAndroid Build Coastguard Worker       value_boot_image_reference(kInvalidReference) {}
121*795d594fSAndroid Build Coastguard Worker 
ComputeValueOfInfo(HInvoke * invoke,const CompilerOptions & compiler_options,ArtField * value_field,int32_t low,int32_t length,size_t base)122*795d594fSAndroid Build Coastguard Worker IntrinsicVisitor::ValueOfInfo IntrinsicVisitor::ComputeValueOfInfo(
123*795d594fSAndroid Build Coastguard Worker     HInvoke* invoke,
124*795d594fSAndroid Build Coastguard Worker     const CompilerOptions& compiler_options,
125*795d594fSAndroid Build Coastguard Worker     ArtField* value_field,
126*795d594fSAndroid Build Coastguard Worker     int32_t low,
127*795d594fSAndroid Build Coastguard Worker     int32_t length,
128*795d594fSAndroid Build Coastguard Worker     size_t base) {
129*795d594fSAndroid Build Coastguard Worker   ValueOfInfo info;
130*795d594fSAndroid Build Coastguard Worker   info.low = low;
131*795d594fSAndroid Build Coastguard Worker   info.length = length;
132*795d594fSAndroid Build Coastguard Worker   info.value_offset = value_field->GetOffset().Uint32Value();
133*795d594fSAndroid Build Coastguard Worker   if (compiler_options.IsBootImage()) {
134*795d594fSAndroid Build Coastguard Worker     if (invoke->InputAt(0)->IsIntConstant()) {
135*795d594fSAndroid Build Coastguard Worker       int32_t input_value = invoke->InputAt(0)->AsIntConstant()->GetValue();
136*795d594fSAndroid Build Coastguard Worker       uint32_t index = static_cast<uint32_t>(input_value) - static_cast<uint32_t>(info.low);
137*795d594fSAndroid Build Coastguard Worker       if (index < static_cast<uint32_t>(info.length)) {
138*795d594fSAndroid Build Coastguard Worker         info.value_boot_image_reference = IntrinsicObjects::EncodePatch(
139*795d594fSAndroid Build Coastguard Worker             IntrinsicObjects::PatchType::kValueOfObject, index + base);
140*795d594fSAndroid Build Coastguard Worker       } else {
141*795d594fSAndroid Build Coastguard Worker         // Not in the cache.
142*795d594fSAndroid Build Coastguard Worker         info.value_boot_image_reference = ValueOfInfo::kInvalidReference;
143*795d594fSAndroid Build Coastguard Worker       }
144*795d594fSAndroid Build Coastguard Worker     } else {
145*795d594fSAndroid Build Coastguard Worker       info.array_data_boot_image_reference =
146*795d594fSAndroid Build Coastguard Worker           IntrinsicObjects::EncodePatch(IntrinsicObjects::PatchType::kValueOfArray, base);
147*795d594fSAndroid Build Coastguard Worker     }
148*795d594fSAndroid Build Coastguard Worker   } else {
149*795d594fSAndroid Build Coastguard Worker     ScopedObjectAccess soa(Thread::Current());
150*795d594fSAndroid Build Coastguard Worker     ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = GetBootImageLiveObjects();
151*795d594fSAndroid Build Coastguard Worker 
152*795d594fSAndroid Build Coastguard Worker     if (invoke->InputAt(0)->IsIntConstant()) {
153*795d594fSAndroid Build Coastguard Worker       int32_t input_value = invoke->InputAt(0)->AsIntConstant()->GetValue();
154*795d594fSAndroid Build Coastguard Worker       uint32_t index = static_cast<uint32_t>(input_value) - static_cast<uint32_t>(info.low);
155*795d594fSAndroid Build Coastguard Worker       if (index < static_cast<uint32_t>(info.length)) {
156*795d594fSAndroid Build Coastguard Worker         ObjPtr<mirror::Object> object =
157*795d594fSAndroid Build Coastguard Worker             IntrinsicObjects::GetValueOfObject(boot_image_live_objects, base, index);
158*795d594fSAndroid Build Coastguard Worker         info.value_boot_image_reference = CodeGenerator::GetBootImageOffset(object);
159*795d594fSAndroid Build Coastguard Worker       } else {
160*795d594fSAndroid Build Coastguard Worker         // Not in the cache.
161*795d594fSAndroid Build Coastguard Worker         info.value_boot_image_reference = ValueOfInfo::kInvalidReference;
162*795d594fSAndroid Build Coastguard Worker       }
163*795d594fSAndroid Build Coastguard Worker     } else {
164*795d594fSAndroid Build Coastguard Worker       info.array_data_boot_image_reference =
165*795d594fSAndroid Build Coastguard Worker           CodeGenerator::GetBootImageOffset(boot_image_live_objects) +
166*795d594fSAndroid Build Coastguard Worker           IntrinsicObjects::GetValueOfArrayDataOffset(
167*795d594fSAndroid Build Coastguard Worker               boot_image_live_objects, base).Uint32Value();
168*795d594fSAndroid Build Coastguard Worker     }
169*795d594fSAndroid Build Coastguard Worker   }
170*795d594fSAndroid Build Coastguard Worker 
171*795d594fSAndroid Build Coastguard Worker   return info;
172*795d594fSAndroid Build Coastguard Worker }
173*795d594fSAndroid Build Coastguard Worker 
GetReferenceDisableIntrinsicOffset()174*795d594fSAndroid Build Coastguard Worker MemberOffset IntrinsicVisitor::GetReferenceDisableIntrinsicOffset() {
175*795d594fSAndroid Build Coastguard Worker   ScopedObjectAccess soa(Thread::Current());
176*795d594fSAndroid Build Coastguard Worker   // The "disableIntrinsic" is the first static field.
177*795d594fSAndroid Build Coastguard Worker   ArtField* field = GetClassRoot<mirror::Reference>()->GetStaticField(0);
178*795d594fSAndroid Build Coastguard Worker   DCHECK_STREQ(field->GetName(), "disableIntrinsic");
179*795d594fSAndroid Build Coastguard Worker   return field->GetOffset();
180*795d594fSAndroid Build Coastguard Worker }
181*795d594fSAndroid Build Coastguard Worker 
GetReferenceSlowPathEnabledOffset()182*795d594fSAndroid Build Coastguard Worker MemberOffset IntrinsicVisitor::GetReferenceSlowPathEnabledOffset() {
183*795d594fSAndroid Build Coastguard Worker   ScopedObjectAccess soa(Thread::Current());
184*795d594fSAndroid Build Coastguard Worker   // The "slowPathEnabled" is the second static field.
185*795d594fSAndroid Build Coastguard Worker   ArtField* field = GetClassRoot<mirror::Reference>()->GetStaticField(1);
186*795d594fSAndroid Build Coastguard Worker   DCHECK_STREQ(field->GetName(), "slowPathEnabled");
187*795d594fSAndroid Build Coastguard Worker   return field->GetOffset();
188*795d594fSAndroid Build Coastguard Worker }
189*795d594fSAndroid Build Coastguard Worker 
CreateReferenceGetReferentLocations(HInvoke * invoke,CodeGenerator * codegen)190*795d594fSAndroid Build Coastguard Worker void IntrinsicVisitor::CreateReferenceGetReferentLocations(HInvoke* invoke,
191*795d594fSAndroid Build Coastguard Worker                                                            CodeGenerator* codegen) {
192*795d594fSAndroid Build Coastguard Worker   if (!CanReferenceBootImageObjects(invoke, codegen->GetCompilerOptions())) {
193*795d594fSAndroid Build Coastguard Worker     return;
194*795d594fSAndroid Build Coastguard Worker   }
195*795d594fSAndroid Build Coastguard Worker 
196*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = codegen->GetGraph()->GetAllocator();
197*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
198*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
199*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
200*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
201*795d594fSAndroid Build Coastguard Worker }
202*795d594fSAndroid Build Coastguard Worker 
CreateReferenceRefersToLocations(HInvoke * invoke,CodeGenerator * codegen)203*795d594fSAndroid Build Coastguard Worker void IntrinsicVisitor::CreateReferenceRefersToLocations(HInvoke* invoke, CodeGenerator* codegen) {
204*795d594fSAndroid Build Coastguard Worker   if (codegen->EmitNonBakerReadBarrier()) {
205*795d594fSAndroid Build Coastguard Worker     // Unimplemented for non-Baker read barrier.
206*795d594fSAndroid Build Coastguard Worker     return;
207*795d594fSAndroid Build Coastguard Worker   }
208*795d594fSAndroid Build Coastguard Worker 
209*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator();
210*795d594fSAndroid Build Coastguard Worker   LocationSummary* locations =
211*795d594fSAndroid Build Coastguard Worker       new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified);
212*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(0, Location::RequiresRegister());
213*795d594fSAndroid Build Coastguard Worker   locations->SetInAt(1, Location::RequiresRegister());
214*795d594fSAndroid Build Coastguard Worker   locations->SetOut(Location::RequiresRegister());
215*795d594fSAndroid Build Coastguard Worker }
216*795d594fSAndroid Build Coastguard Worker 
AssertNonMovableStringClass()217*795d594fSAndroid Build Coastguard Worker void IntrinsicVisitor::AssertNonMovableStringClass() {
218*795d594fSAndroid Build Coastguard Worker   if (kIsDebugBuild) {
219*795d594fSAndroid Build Coastguard Worker     ScopedObjectAccess soa(Thread::Current());
220*795d594fSAndroid Build Coastguard Worker     ObjPtr<mirror::Class> string_class = GetClassRoot<mirror::String>();
221*795d594fSAndroid Build Coastguard Worker     CHECK(!art::Runtime::Current()->GetHeap()->IsMovableObject(string_class));
222*795d594fSAndroid Build Coastguard Worker   }
223*795d594fSAndroid Build Coastguard Worker }
224*795d594fSAndroid Build Coastguard Worker 
InsertFpToIntegralIntrinsic(HInvokeStaticOrDirect * invoke,size_t input_index)225*795d594fSAndroid Build Coastguard Worker void InsertFpToIntegralIntrinsic(HInvokeStaticOrDirect* invoke, size_t input_index) {
226*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(invoke->GetCodePtrLocation(), CodePtrLocation::kCallCriticalNative);
227*795d594fSAndroid Build Coastguard Worker   DCHECK(!invoke->GetBlock()->GetGraph()->IsDebuggable())
228*795d594fSAndroid Build Coastguard Worker       << "Unexpected direct @CriticalNative call in a debuggable graph!";
229*795d594fSAndroid Build Coastguard Worker   DCHECK_LT(input_index, invoke->GetNumberOfArguments());
230*795d594fSAndroid Build Coastguard Worker   HInstruction* input = invoke->InputAt(input_index);
231*795d594fSAndroid Build Coastguard Worker   DataType::Type input_type = input->GetType();
232*795d594fSAndroid Build Coastguard Worker   DCHECK(DataType::IsFloatingPointType(input_type));
233*795d594fSAndroid Build Coastguard Worker   bool is_double = (input_type == DataType::Type::kFloat64);
234*795d594fSAndroid Build Coastguard Worker   DataType::Type converted_type = is_double ? DataType::Type::kInt64 : DataType::Type::kInt32;
235*795d594fSAndroid Build Coastguard Worker   ArtMethod* resolved_method = is_double
236*795d594fSAndroid Build Coastguard Worker       ? WellKnownClasses::java_lang_Double_doubleToRawLongBits
237*795d594fSAndroid Build Coastguard Worker       : WellKnownClasses::java_lang_Float_floatToRawIntBits;
238*795d594fSAndroid Build Coastguard Worker   DCHECK(resolved_method != nullptr);
239*795d594fSAndroid Build Coastguard Worker   DCHECK(resolved_method->IsIntrinsic());
240*795d594fSAndroid Build Coastguard Worker   MethodReference target_method(nullptr, 0);
241*795d594fSAndroid Build Coastguard Worker   {
242*795d594fSAndroid Build Coastguard Worker     ScopedObjectAccess soa(Thread::Current());
243*795d594fSAndroid Build Coastguard Worker     target_method =
244*795d594fSAndroid Build Coastguard Worker         MethodReference(resolved_method->GetDexFile(), resolved_method->GetDexMethodIndex());
245*795d594fSAndroid Build Coastguard Worker   }
246*795d594fSAndroid Build Coastguard Worker   // Use arbitrary dispatch info that does not require the method argument.
247*795d594fSAndroid Build Coastguard Worker   HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
248*795d594fSAndroid Build Coastguard Worker       MethodLoadKind::kBssEntry,
249*795d594fSAndroid Build Coastguard Worker       CodePtrLocation::kCallArtMethod,
250*795d594fSAndroid Build Coastguard Worker       /*method_load_data=*/ 0u
251*795d594fSAndroid Build Coastguard Worker   };
252*795d594fSAndroid Build Coastguard Worker   HBasicBlock* block = invoke->GetBlock();
253*795d594fSAndroid Build Coastguard Worker   ArenaAllocator* allocator = block->GetGraph()->GetAllocator();
254*795d594fSAndroid Build Coastguard Worker   HInvokeStaticOrDirect* new_input = new (allocator) HInvokeStaticOrDirect(
255*795d594fSAndroid Build Coastguard Worker       allocator,
256*795d594fSAndroid Build Coastguard Worker       /*number_of_arguments=*/ 1u,
257*795d594fSAndroid Build Coastguard Worker       /*number_of_out_vregs=*/ is_double ? 2u : 1u,
258*795d594fSAndroid Build Coastguard Worker       converted_type,
259*795d594fSAndroid Build Coastguard Worker       invoke->GetDexPc(),
260*795d594fSAndroid Build Coastguard Worker       /*method_reference=*/ MethodReference(nullptr, dex::kDexNoIndex),
261*795d594fSAndroid Build Coastguard Worker       resolved_method,
262*795d594fSAndroid Build Coastguard Worker       dispatch_info,
263*795d594fSAndroid Build Coastguard Worker       kStatic,
264*795d594fSAndroid Build Coastguard Worker       target_method,
265*795d594fSAndroid Build Coastguard Worker       HInvokeStaticOrDirect::ClinitCheckRequirement::kNone,
266*795d594fSAndroid Build Coastguard Worker       /*enable_intrinsic_opt=*/ true);
267*795d594fSAndroid Build Coastguard Worker   // The intrinsic has no side effects and does not need the environment.
268*795d594fSAndroid Build Coastguard Worker   new_input->SetSideEffects(SideEffects::None());
269*795d594fSAndroid Build Coastguard Worker   IntrinsicOptimizations opt(new_input);
270*795d594fSAndroid Build Coastguard Worker   opt.SetDoesNotNeedEnvironment();
271*795d594fSAndroid Build Coastguard Worker   new_input->SetRawInputAt(0u, input);
272*795d594fSAndroid Build Coastguard Worker   block->InsertInstructionBefore(new_input, invoke);
273*795d594fSAndroid Build Coastguard Worker   invoke->ReplaceInput(new_input, input_index);
274*795d594fSAndroid Build Coastguard Worker }
275*795d594fSAndroid Build Coastguard Worker 
276*795d594fSAndroid Build Coastguard Worker }  // namespace art
277