blob: 649496478a56b0d5566030eca5bd58bd6a493483 [file] [log] [blame]
Vladimir Markodc151b22015-10-15 18:02:30 +01001/*
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#include "sharpening.h"
18
19#include "code_generator.h"
20#include "utils/dex_cache_arrays_layout-inl.h"
21#include "driver/compiler_driver.h"
22#include "nodes.h"
23
24namespace art {
25
26void HSharpening::Run() {
27 // We don't care about the order of the blocks here.
28 for (HBasicBlock* block : graph_->GetReversePostOrder()) {
29 for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
30 HInstruction* instruction = it.Current();
31 if (instruction->IsInvokeStaticOrDirect()) {
32 ProcessInvokeStaticOrDirect(instruction->AsInvokeStaticOrDirect());
33 }
34 // TODO: Move the sharpening of invoke-virtual/-interface/-super from HGraphBuilder
35 // here. Rewrite it to avoid the CompilerDriver's reliance on verifier data
36 // because we know the type better when inlining.
37 // TODO: HLoadClass, HLoadString - select PC relative dex cache array access if
38 // available.
39 }
40 }
41}
42
43void HSharpening::ProcessInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
44 if (invoke->IsStringInit()) {
45 // Not using the dex cache arrays. But we could still try to use a better dispatch...
46 // TODO: Use direct_method and direct_code for the appropriate StringFactory method.
47 return;
48 }
49
50 // TODO: Avoid CompilerDriver.
51 InvokeType invoke_type = invoke->GetOriginalInvokeType();
52 MethodReference target_method(&graph_->GetDexFile(), invoke->GetDexMethodIndex());
53 int vtable_idx;
54 uintptr_t direct_code, direct_method;
55 bool success = compiler_driver_->ComputeInvokeInfo(
56 &compilation_unit_,
57 invoke->GetDexPc(),
58 false /* update_stats: already updated in builder */,
59 true /* enable_devirtualization */,
60 &invoke_type,
61 &target_method,
62 &vtable_idx,
63 &direct_code,
64 &direct_method);
65 DCHECK(success);
66 DCHECK_EQ(invoke_type, invoke->GetInvokeType());
67 DCHECK_EQ(target_method.dex_file, invoke->GetTargetMethod().dex_file);
68 DCHECK_EQ(target_method.dex_method_index, invoke->GetTargetMethod().dex_method_index);
69
70 HInvokeStaticOrDirect::MethodLoadKind method_load_kind;
71 HInvokeStaticOrDirect::CodePtrLocation code_ptr_location;
72 uint64_t method_load_data = 0u;
73 uint64_t direct_code_ptr = 0u;
74
75 HGraph* outer_graph = codegen_->GetGraph();
76 if (target_method.dex_file == &outer_graph->GetDexFile() &&
77 target_method.dex_method_index == outer_graph->GetMethodIdx()) {
78 method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kRecursive;
79 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallSelf;
80 } else {
81 if (direct_method != 0u) { // Should we use a direct pointer to the method?
82 if (direct_method != static_cast<uintptr_t>(-1)) { // Is the method pointer known now?
83 method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress;
84 method_load_data = direct_method;
85 } else { // The direct pointer will be known at link time.
86 method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup;
87 }
88 } else { // Use dex cache.
89 DCHECK_EQ(target_method.dex_file, &graph_->GetDexFile());
90 DexCacheArraysLayout layout =
91 compiler_driver_->GetDexCacheArraysLayout(target_method.dex_file);
92 if (layout.Valid()) { // Can we use PC-relative access to the dex cache arrays?
93 method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative;
94 method_load_data = layout.MethodOffset(target_method.dex_method_index);
95 } else { // We must go through the ArtMethod's pointer to resolved methods.
96 method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod;
97 }
98 }
99 if (direct_code != 0u) { // Should we use a direct pointer to the code?
100 if (direct_code != static_cast<uintptr_t>(-1)) { // Is the code pointer known now?
101 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallDirect;
102 direct_code_ptr = direct_code;
103 } else if (compiler_driver_->IsImage() ||
104 target_method.dex_file == &graph_->GetDexFile()) {
105 // Use PC-relative calls for invokes within a multi-dex oat file.
106 // TODO: Recognize when the target dex file is within the current oat file for
107 // app compilation. At the moment we recognize only the boot image as multi-dex.
108 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative;
109 } else { // The direct pointer will be known at link time.
110 // NOTE: This is used for app->boot calls when compiling an app against
111 // a relocatable but not yet relocated image.
112 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup;
113 }
114 } else { // We must use the code pointer from the ArtMethod.
115 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
116 }
117 }
118
119 if (graph_->IsDebuggable()) {
120 // For debuggable apps always use the code pointer from ArtMethod
121 // so that we don't circumvent instrumentation stubs if installed.
122 code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod;
123 }
124
125 HInvokeStaticOrDirect::DispatchInfo desired_dispatch_info = {
126 method_load_kind, code_ptr_location, method_load_data, direct_code_ptr
127 };
128 HInvokeStaticOrDirect::DispatchInfo dispatch_info =
129 codegen_->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info,
130 invoke->GetTargetMethod());
131 invoke->SetDispatchInfo(dispatch_info);
132}
133
134} // namespace art