blob: 11d42a41ee7606fe98b150bfb0fb04b6d2c9b5b2 [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);
52 MethodReference target_method(nullptr, 0);
53 {
54 ScopedObjectAccess soa(Thread::Current());
55 target_method =
56 MethodReference(resolved_method->GetDexFile(), resolved_method->GetDexMethodIndex());
57 }
58 // Use arbitrary dispatch info that does not require the method argument.
59 HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
Nicolas Geoffray6d69b522020-09-23 14:47:28 +010060 MethodLoadKind::kBssEntry,
61 CodePtrLocation::kCallArtMethod,
Vladimir Markod3e9c622020-08-05 12:20:28 +010062 /*method_load_data=*/ 0u
63 };
64 HBasicBlock* block = invoke->GetBlock();
65 ArenaAllocator* allocator = block->GetGraph()->GetAllocator();
66 HInvokeStaticOrDirect* new_input = new (allocator) HInvokeStaticOrDirect(
67 allocator,
68 /*number_of_arguments=*/ 1u,
69 converted_type,
70 invoke->GetDexPc(),
Nicolas Geoffraye6c0f2a2020-09-07 08:30:52 +010071 /*method_reference=*/ MethodReference(nullptr, dex::kDexNoIndex),
Vladimir Markod3e9c622020-08-05 12:20:28 +010072 resolved_method,
73 dispatch_info,
74 kStatic,
75 target_method,
76 HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
77 // The intrinsic has no side effects and does not need environment or dex cache on ARM.
78 new_input->SetSideEffects(SideEffects::None());
79 IntrinsicOptimizations opt(new_input);
Vladimir Markod3e9c622020-08-05 12:20:28 +010080 opt.SetDoesNotNeedEnvironment();
81 new_input->SetRawInputAt(0u, input);
82 block->InsertInstructionBefore(new_input, invoke);
83 invoke->ReplaceInput(new_input, i);
84 }
85 reg = next_reg;
86 }
87}
88
89bool CriticalNativeAbiFixupArm::Run() {
90 if (!graph_->HasDirectCriticalNativeCall()) {
91 return false;
92 }
93
94 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
95 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
96 HInstruction* instruction = it.Current();
97 if (instruction->IsInvokeStaticOrDirect() &&
98 instruction->AsInvokeStaticOrDirect()->GetCodePtrLocation() ==
Nicolas Geoffray6d69b522020-09-23 14:47:28 +010099 CodePtrLocation::kCallCriticalNative) {
Vladimir Markod3e9c622020-08-05 12:20:28 +0100100 FixUpArguments(instruction->AsInvokeStaticOrDirect());
101 }
102 }
103 }
104 return true;
105}
106
107} // namespace arm
108} // namespace art