summaryrefslogtreecommitdiff
path: root/runtime/instrumentation-inl.h
blob: 3b035ea71b71ca8dffa03de49ed40db9338c5cdd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef ART_RUNTIME_INSTRUMENTATION_INL_H_
#define ART_RUNTIME_INSTRUMENTATION_INL_H_

#include "instrumentation.h"

#include "art_method-inl.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/heap.h"
#include "jit/jit.h"
#include "runtime.h"

namespace art HIDDEN {
namespace instrumentation {

inline bool Instrumentation::CanUseAotCode(const void* quick_code) {
  if (quick_code == nullptr) {
    return false;
  }
  Runtime* runtime = Runtime::Current();
  // For simplicity, we never use AOT code for debuggable.
  if (runtime->IsJavaDebuggable()) {
    return false;
  }

  if (runtime->IsNativeDebuggable()) {
    DCHECK(runtime->UseJitCompilation() && runtime->GetJit()->JitAtFirstUse());
    // If we are doing native debugging, ignore application's AOT code,
    // since we want to JIT it (at first use) with extra stackmaps for native
    // debugging. We keep however all AOT code from the boot image,
    // since the JIT-at-first-use is blocking and would result in non-negligible
    // startup performance impact.
    return runtime->GetHeap()->IsInBootImageOatFile(quick_code);
  }

  return true;
}

inline const void* Instrumentation::GetInitialEntrypoint(uint32_t method_access_flags,
                                                         const void* aot_code) {
  if (!ArtMethod::IsInvokable(method_access_flags)) {
    return GetQuickToInterpreterBridge();
  }

  // Special case if we need an initialization check.
  if (ArtMethod::NeedsClinitCheckBeforeCall(method_access_flags)) {
    // If we have code but the method needs a class initialization check before calling that code,
    // install the resolution stub that will perform the check. It will be replaced by the proper
    // entry point by `ClassLinker::FixupStaticTrampolines()` after initializing class.
    // Note: This mimics the logic in image_writer.cc that installs the resolution stub only
    // if we have compiled code or we can execute nterp, and the method needs a class
    // initialization check.
    return (aot_code != nullptr || ArtMethod::IsNative(method_access_flags))
        ? GetQuickResolutionStub()
        : GetQuickToInterpreterBridge();
  }

  // Use the provided AOT code if possible.
  if (CanUseAotCode(aot_code)) {
    return aot_code;
  }

  // Use default entrypoints.
  return ArtMethod::IsNative(method_access_flags) ? GetQuickGenericJniStub()
                                                  : GetQuickToInterpreterBridge();
}


inline bool Instrumentation::InitialEntrypointNeedsInstrumentationStubs() {
  return IsForcedInterpretOnly() || EntryExitStubsInstalled();
}

inline void Instrumentation::InitializeMethodsCode(ArtMethod* method,
                                                   const void* entrypoint,
                                                   PointerSize pointer_size) {
  if (kIsDebugBuild) {
    // Entrypoint should be uninitialized.
    CHECK(method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size) == nullptr)
        << method->PrettyMethod();
    // We initialize the entrypoint while loading the class, well before the class
    // is verified and Nterp entrypoint is allowed. We prefer to check for resolved
    // because a verified class may lose its "verified" status (by becoming erroneous)
    // but the resolved status is always kept (as "resolved erroneous" if needed).
    CHECK(!method->GetDeclaringClass()->IsResolved());
    CHECK_NE(entrypoint, interpreter::GetNterpEntryPoint()) << method->PrettyMethod();
    if (InitialEntrypointNeedsInstrumentationStubs()) {
      const void* expected =
          method->IsNative() ? GetQuickGenericJniStub() : GetQuickToInterpreterBridge();
      CHECK_EQ(entrypoint, expected) << method->PrettyMethod() << " " << method->IsNative();
    } else if (method->NeedsClinitCheckBeforeCall()) {
      if (method->IsNative()) {
        CHECK_EQ(entrypoint, GetQuickResolutionStub());
      } else {
        // We do not have the original `aot_code` to determine which entrypoint to expect.
        CHECK(entrypoint == GetQuickResolutionStub() ||
              entrypoint == GetQuickToInterpreterBridge());
      }
    } else {
      bool is_stub = (entrypoint == GetQuickToInterpreterBridge()) ||
                     (entrypoint == GetQuickGenericJniStub()) ||
                     (entrypoint == GetQuickResolutionStub());
      const void* aot_code = is_stub ? nullptr : entrypoint;
      const void* initial = GetInitialEntrypoint(method->GetAccessFlags(), aot_code);
      CHECK_EQ(initial, entrypoint)
          << method->PrettyMethod() << " 0x" << std::hex << method->GetAccessFlags();
    }
  }
  method->SetEntryPointFromQuickCompiledCodePtrSize(entrypoint, pointer_size);
}

}  // namespace instrumentation
}  // namespace art

#endif  // ART_RUNTIME_INSTRUMENTATION_INL_H_