blob: 3c4db4bca7b37fb5eec6d8e09d9ed3d72870b280 [file] [log] [blame]
Vladimir Markod3e9c622020-08-05 12:20:28 +01001/*
2 * Copyright (C) 2020 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#include "critical_native_abi_fixup_arm.h"
18
19#include "art_method-inl.h"
20#include "intrinsics.h"
21#include "jni/jni_internal.h"
22#include "nodes.h"
23#include "scoped_thread_state_change-inl.h"
24#include "well_known_classes.h"
25
26namespace art {
27namespace arm {
28
29// Fix up FP arguments passed in core registers for call to @CriticalNative by inserting fake calls
30// to Float.floatToRawIntBits() or Double.doubleToRawLongBits() to satisfy type consistency checks.
31static void FixUpArguments(HInvokeStaticOrDirect* invoke) {
Nicolas Geoffray6d69b522020-09-23 14:47:28 +010032 DCHECK_EQ(invoke->GetCodePtrLocation(), CodePtrLocation::kCallCriticalNative);
Vladimir Markod3e9c622020-08-05 12:20:28 +010033 size_t reg = 0u;
34 for (size_t i = 0, num_args = invoke->GetNumberOfArguments(); i != num_args; ++i) {
35 HInstruction* input = invoke->InputAt(i);
36 DataType::Type input_type = input->GetType();
37 size_t next_reg = reg + 1u;
38 if (DataType::Is64BitType(input_type)) {
39 reg = RoundUp(reg, 2u);
40 next_reg = reg + 2u;
41 }
42 if (reg == 4u) {
43 break; // Remaining arguments are passed on stack.
44 }
45 if (DataType::IsFloatingPointType(input_type)) {
46 bool is_double = (input_type == DataType::Type::kFloat64);
47 DataType::Type converted_type = is_double ? DataType::Type::kInt64 : DataType::Type::kInt32;
48 jmethodID known_method = is_double ? WellKnownClasses::java_lang_Double_doubleToRawLongBits
49 : WellKnownClasses::java_lang_Float_floatToRawIntBits;
50 ArtMethod* resolved_method = jni::DecodeArtMethod(known_method);
51 DCHECK(resolved_method != nullptr);
Vladimir Markod4290262021-05-21 16:36:23 +010052 DCHECK(resolved_method->IsIntrinsic());
Vladimir Markod3e9c622020-08-05 12:20:28 +010053 MethodReference target_method(nullptr, 0);
54 {
55 ScopedObjectAccess soa(Thread::Current());
56 target_method =
57 MethodReference(resolved_method->GetDexFile(), resolved_method->GetDexMethodIndex());
58 }
59 // Use arbitrary dispatch info that does not require the method argument.
60 HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
Nicolas Geoffray6d69b522020-09-23 14:47:28 +010061 MethodLoadKind::kBssEntry,
62 CodePtrLocation::kCallArtMethod,
Vladimir Markod3e9c622020-08-05 12:20:28 +010063 /*method_load_data=*/ 0u
64 };
65 HBasicBlock* block = invoke->GetBlock();
66 ArenaAllocator* allocator = block->GetGraph()->GetAllocator();
67 HInvokeStaticOrDirect* new_input = new (allocator) HInvokeStaticOrDirect(
68 allocator,
69 /*number_of_arguments=*/ 1u,
70 converted_type,
71 invoke->GetDexPc(),
Nicolas Geoffraye6c0f2a2020-09-07 08:30:52 +010072 /*method_reference=*/ MethodReference(nullptr, dex::kDexNoIndex),
Vladimir Markod3e9c622020-08-05 12:20:28 +010073 resolved_method,
74 dispatch_info,
75 kStatic,
76 target_method,
77 HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
78 // The intrinsic has no side effects and does not need environment or dex cache on ARM.
79 new_input->SetSideEffects(SideEffects::None());
80 IntrinsicOptimizations opt(new_input);
Vladimir Markod3e9c622020-08-05 12:20:28 +010081 opt.SetDoesNotNeedEnvironment();
82 new_input->SetRawInputAt(0u, input);
83 block->InsertInstructionBefore(new_input, invoke);
84 invoke->ReplaceInput(new_input, i);
85 }
86 reg = next_reg;
87 }
88}
89
90bool CriticalNativeAbiFixupArm::Run() {
91 if (!graph_->HasDirectCriticalNativeCall()) {
92 return false;
93 }
94
95 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
96 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
97 HInstruction* instruction = it.Current();
98 if (instruction->IsInvokeStaticOrDirect() &&
99 instruction->AsInvokeStaticOrDirect()->GetCodePtrLocation() ==
Nicolas Geoffray6d69b522020-09-23 14:47:28 +0100100 CodePtrLocation::kCallCriticalNative) {
Vladimir Markod3e9c622020-08-05 12:20:28 +0100101 FixUpArguments(instruction->AsInvokeStaticOrDirect());
102 }
103 }
104 }
105 return true;
106}
107
108} // namespace arm
109} // namespace art