• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "events/events.h"
17 #include "runtime/bridge/bridge.h"
18 #include "runtime/entrypoints/entrypoints.h"
19 #include "runtime/jit/profiling_data.h"
20 #include "runtime/include/class_linker-inl.h"
21 #include "runtime/include/exceptions.h"
22 #include "runtime/include/locks.h"
23 #include "runtime/include/mem/panda_smart_pointers.h"
24 #include "runtime/include/method-inl.h"
25 #include "runtime/include/runtime.h"
26 #include "runtime/include/panda_vm.h"
27 #include "runtime/include/runtime_notification.h"
28 #include "runtime/include/value-inl.h"
29 #include "runtime/interpreter/frame.h"
30 #include "runtime/interpreter/interpreter.h"
31 #include "libpandabase/utils/hash.h"
32 #include "libpandabase/utils/span.h"
33 #include "libpandabase/utils/utf.h"
34 #include "libpandabase/os/mutex.h"
35 #include "libpandafile/code_data_accessor-inl.h"
36 #include "libpandafile/debug_data_accessor-inl.h"
37 #include "libpandafile/debug_helpers.h"
38 #include "libpandafile/file-inl.h"
39 #include "libpandafile/line_number_program.h"
40 #include "libpandafile/method_data_accessor-inl.h"
41 #include "libpandafile/proto_data_accessor-inl.h"
42 #include "libpandafile/shorty_iterator.h"
43 #include "runtime/handle_base-inl.h"
44 #include "runtime/handle_scope-inl.h"
45 #include "libpandafile/type_helper.h"
46 #include "verification/public.h"
47 #include "verification/util/is_system.h"
48 
49 namespace panda {
50 
Proto(const panda_file::File & pf,panda_file::File::EntityId protoId)51 Method::Proto::Proto(const panda_file::File &pf, panda_file::File::EntityId protoId)
52 {
53     panda_file::ProtoDataAccessor pda(pf, protoId);
54 
55     pda.EnumerateTypes([this](panda_file::Type type) { shorty_.push_back(type); });
56 
57     auto refNum = pda.GetRefNum();
58     for (size_t refIdx = 0; refIdx < refNum; ++refIdx) {
59         auto id = pda.GetReferenceType(refIdx);
60         refTypes_.emplace_back(utf::Mutf8AsCString(pf.GetStringData(id).data));
61     }
62 }
63 
operator ==(const Method::ProtoId & other) const64 bool Method::ProtoId::operator==(const Method::ProtoId &other) const
65 {
66     if (&pf_ == &other.pf_) {
67         return protoId_ == other.protoId_;
68     }
69 
70     panda_file::ProtoDataAccessor pda1(pf_, protoId_);
71     panda_file::ProtoDataAccessor pda2(other.pf_, other.protoId_);
72     return pda1.IsEqual(&pda2);
73 }
74 
operator ==(const Proto & other) const75 bool Method::ProtoId::operator==(const Proto &other) const
76 {
77     const auto &shorties = other.GetShorty();
78     const auto &refTypes = other.GetRefTypes();
79 
80     bool equal = true;
81     size_t shortyIdx = 0;
82     panda_file::ProtoDataAccessor pda(pf_, protoId_);
83     pda.EnumerateTypes([&equal, &shorties, &shortyIdx](panda_file::Type type) {
84         equal = equal && shortyIdx < shorties.size() && type == shorties[shortyIdx];
85         ++shortyIdx;
86     });
87     if (!equal || shortyIdx != shorties.size() || pda.GetRefNum() != refTypes.size()) {
88         return false;
89     }
90 
91     // check ref types
92     for (size_t refIdx = 0; refIdx < refTypes.size(); ++refIdx) {
93         auto id = pda.GetReferenceType(refIdx);
94         if (refTypes[refIdx] != utf::Mutf8AsCString(pf_.GetStringData(id).data)) {
95             return false;
96         }
97     }
98 
99     return true;
100 }
101 
GetReturnTypeDescriptor() const102 std::string_view Method::Proto::GetReturnTypeDescriptor() const
103 {
104     auto retType = GetReturnType();
105     if (!retType.IsPrimitive()) {
106         return refTypes_[0];
107     }
108 
109     switch (retType.GetId()) {
110         case panda_file::Type::TypeId::VOID:
111             return "V";
112         case panda_file::Type::TypeId::U1:
113             return "Z";
114         case panda_file::Type::TypeId::I8:
115             return "B";
116         case panda_file::Type::TypeId::U8:
117             return "H";
118         case panda_file::Type::TypeId::I16:
119             return "S";
120         case panda_file::Type::TypeId::U16:
121             return "C";
122         case panda_file::Type::TypeId::I32:
123             return "I";
124         case panda_file::Type::TypeId::U32:
125             return "U";
126         case panda_file::Type::TypeId::F32:
127             return "F";
128         case panda_file::Type::TypeId::I64:
129             return "J";
130         case panda_file::Type::TypeId::U64:
131             return "Q";
132         case panda_file::Type::TypeId::F64:
133             return "D";
134         case panda_file::Type::TypeId::TAGGED:
135             return "A";
136         default:
137             UNREACHABLE();
138     }
139 }
140 
GetSignature(bool includeReturnType)141 PandaString Method::Proto::GetSignature(bool includeReturnType)
142 {
143     PandaOStringStream signature;
144     signature << "(";
145     auto &shorty = GetShorty();
146     auto &refTypes = GetRefTypes();
147 
148     auto refIt = refTypes.begin();
149     panda_file::Type returnType = shorty[0];
150     if (!returnType.IsPrimitive()) {
151         ++refIt;
152     }
153     auto shortyEnd = shorty.end();
154     auto shortyIt = shorty.begin() + 1;
155     for (; shortyIt != shortyEnd; ++shortyIt) {
156         if ((*shortyIt).IsPrimitive()) {
157             signature << panda_file::Type::GetSignatureByTypeId(*shortyIt);
158         } else {
159             signature << *refIt;
160             ++refIt;
161         }
162     }
163     signature << ")";
164     if (includeReturnType) {
165         if (returnType.IsPrimitive()) {
166             signature << panda_file::Type::GetSignatureByTypeId(returnType);
167         } else {
168             signature << refTypes[0];
169         }
170     }
171 
172     return signature.str();
173 }
174 
GetFullNameHashFromString(const PandaString & str)175 uint32_t Method::GetFullNameHashFromString(const PandaString &str)
176 {
177     return GetHash32String(reinterpret_cast<const uint8_t *>(str.c_str()));
178 }
179 
GetClassNameHashFromString(const PandaString & str)180 uint32_t Method::GetClassNameHashFromString(const PandaString &str)
181 {
182     return GetHash32String(reinterpret_cast<const uint8_t *>(str.c_str()));
183 }
184 
CalcUniqId(const uint8_t * classDescr,const uint8_t * name)185 Method::UniqId Method::CalcUniqId(const uint8_t *classDescr, const uint8_t *name)
186 {
187     auto constexpr HALF = 32ULL;
188     constexpr uint64_t NO_FILE = 0xFFFFFFFFULL << HALF;
189     uint64_t hash = PseudoFnvHashString(classDescr);
190     hash = PseudoFnvHashString(name, hash);
191     return NO_FILE | hash;
192 }
193 
Method(Class * klass,const panda_file::File * pf,panda_file::File::EntityId fileId,panda_file::File::EntityId codeId,uint32_t accessFlags,uint32_t numArgs,const uint16_t * shorty)194 Method::Method(Class *klass, const panda_file::File *pf, panda_file::File::EntityId fileId,
195                panda_file::File::EntityId codeId, uint32_t accessFlags, uint32_t numArgs, const uint16_t *shorty)
196     : accessFlags_(accessFlags),
197       numArgs_(numArgs),
198       stor16Pair_({0, 0}),
199       classWord_(static_cast<ClassHelper::ClassWordSize>(ToObjPtrType(klass))),
200       compiledEntryPoint_(nullptr),
201       pandaFile_(pf),
202       pointer_(),
203 
204       fileId_(fileId),
205       codeId_(codeId),
206       shorty_(shorty)
207 {
208     ResetHotnessCounter();
209 
210     // Atomic with relaxed order reason: data race with native_pointer_ with no synchronization or ordering constraints
211     // imposed on other reads or writes NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
212     pointer_.nativePointer.store(nullptr, std::memory_order_relaxed);
213     SetCompilationStatus(CompilationStage::NOT_COMPILED);
214 }
215 
Invoke(ManagedThread * thread,Value * args,bool proxyCall)216 Value Method::Invoke(ManagedThread *thread, Value *args, bool proxyCall)
217 {
218 #ifndef NDEBUG
219     if (thread->HasPendingException()) {
220         LOG(ERROR, INTERPRETER) << "Has pending exception " << thread->GetException()->ClassAddr<Class>()->GetName();
221         LOG(ERROR, INTERPRETER) << "Before call the method " << GetFullName();
222         StackWalker::Create(ManagedThread::GetCurrent()).Dump(std::cerr);
223     }
224 #endif
225     ASSERT(!thread->HasPendingException());
226     return InvokeImpl<InvokeHelperStatic>(thread, GetNumArgs(), args, proxyCall);
227 }
228 
GetReturnType() const229 PANDA_PUBLIC_API panda_file::Type Method::GetReturnType() const
230 {
231     panda_file::ShortyIterator it(shorty_);
232     return *it;
233 }
234 
GetArgType(size_t idx) const235 panda_file::Type Method::GetArgType(size_t idx) const
236 {
237     if (!IsStatic()) {
238         if (idx == 0) {
239             return panda_file::Type(panda_file::Type::TypeId::REFERENCE);
240         }
241 
242         --idx;
243     }
244 
245     panda_file::ProtoDataAccessor pda(*(pandaFile_),
246                                       panda_file::MethodDataAccessor::GetProtoId(*(pandaFile_), fileId_));
247     return pda.GetArgType(idx);
248 }
249 
GetRefReturnType() const250 panda_file::File::StringData Method::GetRefReturnType() const
251 {
252     ASSERT(GetReturnType().IsReference());
253     panda_file::ProtoDataAccessor pda(*(pandaFile_),
254                                       panda_file::MethodDataAccessor::GetProtoId(*(pandaFile_), fileId_));
255     panda_file::File::EntityId classId = pda.GetReferenceType(0);
256     return pandaFile_->GetStringData(classId);
257 }
258 
GetRefArgType(size_t idx) const259 panda_file::File::StringData Method::GetRefArgType(size_t idx) const
260 {
261     if (!IsStatic()) {
262         if (idx == 0) {
263             return pandaFile_->GetStringData(panda_file::MethodDataAccessor::GetClassId(*(pandaFile_), fileId_));
264         }
265 
266         --idx;
267     }
268 
269     // in case of reference return type first idx corresponds to it
270     if (GetReturnType().IsReference()) {
271         ++idx;
272     }
273     panda_file::ProtoDataAccessor pda(*(pandaFile_),
274                                       panda_file::MethodDataAccessor::GetProtoId(*(pandaFile_), fileId_));
275     panda_file::File::EntityId classId = pda.GetReferenceType(idx);
276     return pandaFile_->GetStringData(classId);
277 }
278 
GetName() const279 panda_file::File::StringData Method::GetName() const
280 {
281     return panda_file::MethodDataAccessor::GetName(*(pandaFile_), fileId_);
282 }
283 
GetFullName(bool withSignature) const284 PandaString Method::GetFullName(bool withSignature) const
285 {
286     PandaOStringStream ss;
287     int refIdx = 0;
288     if (withSignature) {
289         auto returnType = GetReturnType();
290         if (returnType.IsReference()) {
291             ss << ClassHelper::GetName(GetRefReturnType().data) << ' ';
292         } else {
293             ss << returnType << ' ';
294         }
295     }
296     if (GetClass() != nullptr) {
297         ss << PandaString(GetClass()->GetName());
298     }
299     ss << "::" << utf::Mutf8AsCString(Method::GetName().data);
300     if (!withSignature) {
301         return ss.str();
302     }
303     const char *sep = "";
304     ss << '(';
305     panda_file::ProtoDataAccessor pda(*(pandaFile_),
306                                       panda_file::MethodDataAccessor::GetProtoId(*(pandaFile_), fileId_));
307     for (size_t i = 0; i < GetNumArgs(); i++) {
308         auto type = GetEffectiveArgType(i);
309         if (type.IsReference()) {
310             ss << sep << ClassHelper::GetName(GetRefArgType(refIdx++).data);
311         } else {
312             ss << sep << type;
313         }
314         sep = ", ";
315     }
316     ss << ')';
317     return ss.str();
318 }
319 
GetLineNumberAndSourceFile(uint32_t bcOffset) const320 PandaString Method::GetLineNumberAndSourceFile(uint32_t bcOffset) const
321 {
322     PandaOStringStream ss;
323     auto *source = GetClassSourceFile().data;
324     auto lineNum = GetLineNumFromBytecodeOffset(bcOffset);
325 
326     if (source == nullptr) {
327         source = utf::CStringAsMutf8("<unknown>");
328     }
329 
330     ss << source << ":" << lineNum;
331     return ss.str();
332 }
333 
GetClassName() const334 panda_file::File::StringData Method::GetClassName() const
335 {
336     return pandaFile_->GetStringData(panda_file::MethodDataAccessor::GetClassId(*(pandaFile_), fileId_));
337 }
338 
GetProto() const339 Method::Proto Method::GetProto() const
340 {
341     return Proto(*(pandaFile_), panda_file::MethodDataAccessor::GetProtoId(*(pandaFile_), fileId_));
342 }
343 
GetProtoId() const344 Method::ProtoId Method::GetProtoId() const
345 {
346     return ProtoId(*(pandaFile_), panda_file::MethodDataAccessor::GetProtoId(*(pandaFile_), fileId_));
347 }
348 
GetNumericalAnnotation(AnnotationField fieldId) const349 uint32_t Method::GetNumericalAnnotation(AnnotationField fieldId) const
350 {
351     panda_file::MethodDataAccessor mda(*(pandaFile_), fileId_);
352     return mda.GetNumericalAnnotation(fieldId);
353 }
354 
GetStringDataAnnotation(AnnotationField fieldId) const355 panda_file::File::StringData Method::GetStringDataAnnotation(AnnotationField fieldId) const
356 {
357     ASSERT(fieldId >= AnnotationField::STRING_DATA_BEGIN && fieldId <= AnnotationField::STRING_DATA_END);
358     panda_file::MethodDataAccessor mda(*(pandaFile_), fileId_);
359     uint32_t strOffset = mda.GetNumericalAnnotation(fieldId);
360     if (strOffset == 0) {
361         return {0, nullptr};
362     }
363     return pandaFile_->GetStringData(panda_file::File::EntityId(strOffset));
364 }
365 
GetBranchTakenCounter(uint32_t pc)366 int64_t Method::GetBranchTakenCounter(uint32_t pc)
367 {
368     auto profilingData = GetProfilingData();
369     if (profilingData == nullptr) {
370         return 0;
371     }
372     return profilingData->GetBranchTakenCounter(pc);
373 }
374 
GetBranchNotTakenCounter(uint32_t pc)375 int64_t Method::GetBranchNotTakenCounter(uint32_t pc)
376 {
377     auto profilingData = GetProfilingData();
378     if (profilingData == nullptr) {
379         return 0;
380     }
381     return profilingData->GetBranchNotTakenCounter(pc);
382 }
383 
GetThrowTakenCounter(uint32_t pc)384 int64_t Method::GetThrowTakenCounter(uint32_t pc)
385 {
386     auto profilingData = GetProfilingData();
387     if (profilingData == nullptr) {
388         return 0;
389     }
390     return profilingData->GetThrowTakenCounter(pc);
391 }
392 
FindCatchBlockInPandaFile(const Class * cls,uint32_t pc) const393 uint32_t Method::FindCatchBlockInPandaFile(const Class *cls, uint32_t pc) const
394 {
395     ASSERT(!IsAbstract());
396 
397     panda_file::MethodDataAccessor mda(*(pandaFile_), fileId_);
398     panda_file::CodeDataAccessor cda(*(pandaFile_), mda.GetCodeId().value());
399 
400     uint32_t pcOffset = panda_file::INVALID_OFFSET;
401 
402     cda.EnumerateTryBlocks([&pcOffset, cls, pc, this](panda_file::CodeDataAccessor::TryBlock &tryBlock) {
403         if ((tryBlock.GetStartPc() <= pc) && ((tryBlock.GetStartPc() + tryBlock.GetLength()) > pc)) {
404             tryBlock.EnumerateCatchBlocks(
405                 [this, &pcOffset, &cls](panda_file::CodeDataAccessor::CatchBlock &catchBlock) {
406                     auto typeIdx = catchBlock.GetTypeIdx();
407                     if (typeIdx == panda_file::INVALID_INDEX) {
408                         pcOffset = catchBlock.GetHandlerPc();
409                         return false;
410                     }
411 
412                     auto typeId = GetClass()->ResolveClassIndex(typeIdx);
413                     auto *handlerClass = Runtime::GetCurrent()->GetClassLinker()->GetClass(*this, typeId);
414                     if (cls->IsSubClassOf(handlerClass)) {
415                         pcOffset = catchBlock.GetHandlerPc();
416                         return false;
417                     }
418                     return true;
419                 });
420         }
421         return pcOffset == panda_file::INVALID_OFFSET;
422     });
423     return pcOffset;
424 }
425 
FindCatchBlock(const Class * cls,uint32_t pc) const426 uint32_t Method::FindCatchBlock(const Class *cls, uint32_t pc) const
427 {
428     auto *thread = ManagedThread::GetCurrent();
429     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
430     VMHandle<ObjectHeader> exception(thread, thread->GetException());
431     thread->ClearException();
432 
433     auto pcOffset = FindCatchBlockInPandaFile(cls, pc);
434 
435     thread->SetException(exception.GetPtr());
436 
437     return pcOffset;
438 }
439 
GetEffectiveArgType(size_t idx) const440 panda_file::Type Method::GetEffectiveArgType(size_t idx) const
441 {
442     return panda_file::GetEffectiveType(GetArgType(idx));
443 }
444 
GetEffectiveReturnType() const445 panda_file::Type Method::GetEffectiveReturnType() const
446 {
447     return panda_file::GetEffectiveType(GetReturnType());
448 }
449 
GetLineNumFromBytecodeOffset(uint32_t bcOffset) const450 int32_t Method::GetLineNumFromBytecodeOffset(uint32_t bcOffset) const
451 {
452     panda_file::MethodDataAccessor mda(*(pandaFile_), fileId_);
453     return panda_file::debug_helpers::GetLineNumber(mda, bcOffset, pandaFile_);
454 }
455 
GetClassSourceFile() const456 panda_file::File::StringData Method::GetClassSourceFile() const
457 {
458     panda_file::ClassDataAccessor cda(*(pandaFile_), GetClass()->GetFileId());
459     auto sourceFileId = cda.GetSourceFileId();
460     if (!sourceFileId) {
461         return {0, nullptr};
462     }
463 
464     return pandaFile_->GetStringData(sourceFileId.value());
465 }
466 
IsVerified() const467 bool Method::IsVerified() const
468 {
469     if (IsIntrinsic()) {
470         return true;
471     }
472     auto stage = GetVerificationStage();
473     return stage == VerificationStage::VERIFIED_OK || stage == VerificationStage::VERIFIED_FAIL;
474 }
475 
SetVerified(bool result)476 void Method::SetVerified(bool result)
477 {
478     if (IsIntrinsic()) {
479         return;
480     }
481     SetVerificationStage(result ? VerificationStage::VERIFIED_OK : VerificationStage::VERIFIED_FAIL);
482 }
483 
Verify()484 bool Method::Verify()
485 {
486     if (IsVerified()) {
487         return true;
488     }
489     auto &&options = Runtime::GetCurrent()->GetOptions();
490     auto mode = options.GetVerificationMode();
491     auto service = Runtime::GetCurrent()->GetVerifierService();
492     if (service == nullptr) {
493         ASSERT(mode == VerificationMode::DISABLED);
494         // set VERIFIED_OK status in order not to go into Method::Verify() anymore,
495         // since the verifier cannot be enabled during the execution of the managed code
496         if (!IsIntrinsic()) {
497             SetVerificationStage(VerificationStage::VERIFIED_OK);
498         }
499         return true;
500     }
501     if (!options.IsVerifyRuntimeLibraries() && verifier::IsSystemClass(GetClass())) {
502         LOG(DEBUG, VERIFIER) << "Skipping verification of system method " << GetFullName(true);
503         return true;
504     }
505     return verifier::Verify(service, this, mode) == verifier::Status::OK;
506 }
507 
StartProfiling()508 void Method::StartProfiling()
509 {
510 #ifdef PANDA_WITH_ECMASCRIPT
511     // Object handles can be created during class initialization, so check lock state only after GC is started.
512     ASSERT(!ManagedThread::GetCurrent()->GetVM()->GetGC()->IsGCRunning() ||
513            PandaVM::GetCurrent()->GetMutatorLock()->HasLock() ||
514            ManagedThread::GetCurrent()->GetThreadLang() == panda::panda_file::SourceLang::ECMASCRIPT);
515 #else
516     ASSERT(!ManagedThread::GetCurrent()->GetVM()->GetGC()->IsGCRunning() ||
517            PandaVM::GetCurrent()->GetMutatorLock()->HasLock());
518 #endif
519 
520     // Some thread already started profiling
521     if (IsProfilingWithoutLock()) {
522         return;
523     }
524 
525     mem::InternalAllocatorPtr allocator = Runtime::GetCurrent()->GetInternalAllocator();
526     PandaVector<uint32_t> vcalls;
527     PandaVector<uint32_t> branches;
528     PandaVector<uint32_t> throws;
529 
530     Span<const uint8_t> instructions(GetInstructions(), GetCodeSize());
531     for (BytecodeInstruction inst(instructions.begin()); inst.GetAddress() < instructions.end();
532          inst = inst.GetNext()) {
533         if (inst.HasFlag(BytecodeInstruction::Flags::CALL_VIRT)) {
534             vcalls.push_back(inst.GetAddress() - GetInstructions());
535         }
536         if (inst.HasFlag(BytecodeInstruction::Flags::JUMP)) {
537             branches.push_back(inst.GetAddress() - GetInstructions());
538         }
539         if (inst.IsThrow(BytecodeInstruction::Exceptions::X_THROW)) {
540             throws.push_back(inst.GetAddress() - GetInstructions());
541         }
542     }
543     if (vcalls.empty() && branches.empty() && throws.empty()) {
544         return;
545     }
546     ASSERT(std::is_sorted(vcalls.begin(), vcalls.end()));
547 
548     auto data = allocator->Alloc(RoundUp(RoundUp(RoundUp(sizeof(ProfilingData), alignof(CallSiteInlineCache)) +
549                                                      sizeof(CallSiteInlineCache) * vcalls.size(),
550                                                  alignof(BranchData)) +
551                                              sizeof(BranchData) * branches.size(),
552                                          alignof(ThrowData)) +
553                                  sizeof(ThrowData) * throws.size());
554     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
555     auto vcallsMem = reinterpret_cast<uint8_t *>(data) + RoundUp(sizeof(ProfilingData), alignof(CallSiteInlineCache));
556     auto branchesDataOffset = RoundUp(RoundUp(sizeof(ProfilingData), alignof(CallSiteInlineCache)) +
557                                           sizeof(CallSiteInlineCache) * vcalls.size(),
558                                       alignof(BranchData));
559     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
560     auto branchesMem = reinterpret_cast<uint8_t *>(data) + branchesDataOffset;
561 
562     auto throwsDataOffset = RoundUp(branchesDataOffset + sizeof(BranchData) * branches.size(), alignof(ThrowData));
563     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
564     auto throwsMem = reinterpret_cast<uint8_t *>(data) + throwsDataOffset;
565 
566     auto profilingData =
567         new (data) ProfilingData(CallSiteInlineCache::From(vcallsMem, vcalls), BranchData::From(branchesMem, branches),
568                                  ThrowData::From(throwsMem, throws));
569 
570     ProfilingData *oldValue = nullptr;
571     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
572     while (!pointer_.profilingData.compare_exchange_weak(oldValue, profilingData)) {
573         if (oldValue != nullptr) {
574             // We're late, some thread already started profiling.
575             allocator->Delete(data);
576             return;
577         }
578     }
579     EVENT_INTERP_PROFILING(events::InterpProfilingAction::START, GetFullName(), vcalls.size());
580 }
581 
StopProfiling()582 void Method::StopProfiling()
583 {
584     ASSERT(!ManagedThread::GetCurrent()->GetVM()->GetGC()->IsGCRunning() ||
585            PandaVM::GetCurrent()->GetMutatorLock()->HasLock());
586 
587     if (!IsProfilingWithoutLock()) {
588         return;
589     }
590 
591     EVENT_INTERP_PROFILING(events::InterpProfilingAction::STOP, GetFullName(),
592                            GetProfilingData()->GetInlineCaches().size());
593 
594     mem::InternalAllocatorPtr allocator = Runtime::GetCurrent()->GetInternalAllocator();
595     allocator->Free(GetProfilingData());
596     // Atomic with release order reason: data race with profiling_data_ with dependecies on writes before the store
597     // which should become visible acquire NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
598     pointer_.profilingData.store(nullptr, std::memory_order_release);
599 }
600 
IsProxy() const601 bool Method::IsProxy() const
602 {
603     return GetClass()->IsProxy();
604 }
605 
606 /* static */
GetInitialHotnessCounter()607 int16_t Method::GetInitialHotnessCounter()
608 {
609     if (!Runtime::GetCurrent()->IsJitEnabled()) {
610         return std::numeric_limits<int16_t>::max();
611     }
612 
613     auto &options = Runtime::GetOptions();
614     uint32_t threshold = options.GetCompilerHotnessThreshold();
615     uint32_t profThreshold = options.GetCompilerProfilingThreshold();
616     return std::min(threshold, profThreshold);
617 }
618 
ResetHotnessCounter()619 void Method::ResetHotnessCounter()
620 {
621     stor16Pair_.hotnessCounter = GetInitialHotnessCounter();
622 }
623 
624 }  // namespace panda
625