• 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 "verification/config/config_load.h"
17 #include "verification/config/context/context.h"
18 #include "verification/config/debug_breakpoint/breakpoint_private.h"
19 #include "verification/config/whitelist/whitelist_private.h"
20 #include "verification/jobs/thread_pool.h"
21 #include "verification/cache/results_cache.h"
22 #include "verification/util/is_system.h"
23 
24 #include "events/events.h"
25 #include "runtime/bridge/bridge.h"
26 #include "runtime/entrypoints/entrypoints.h"
27 #include "runtime/jit/profiling_data.h"
28 #include "runtime/include/class_linker-inl.h"
29 #include "runtime/include/exceptions.h"
30 #include "runtime/include/locks.h"
31 #include "runtime/include/mem/panda_smart_pointers.h"
32 #include "runtime/include/method-inl.h"
33 #include "runtime/include/runtime.h"
34 #include "runtime/include/panda_vm.h"
35 #include "runtime/include/runtime_notification.h"
36 #include "runtime/include/value-inl.h"
37 #include "runtime/interpreter/frame.h"
38 #include "runtime/interpreter/interpreter.h"
39 #include "libpandabase/utils/hash.h"
40 #include "libpandabase/utils/span.h"
41 #include "libpandabase/utils/utf.h"
42 #include "libpandabase/os/mutex.h"
43 #include "libpandafile/code_data_accessor-inl.h"
44 #include "libpandafile/debug_data_accessor-inl.h"
45 #include "libpandafile/debug_helpers.h"
46 #include "libpandafile/file-inl.h"
47 #include "libpandafile/line_number_program.h"
48 #include "libpandafile/method_data_accessor-inl.h"
49 #include "libpandafile/proto_data_accessor-inl.h"
50 #include "libpandafile/shorty_iterator.h"
51 #include "runtime/handle_base-inl.h"
52 #include "runtime/handle_scope-inl.h"
53 #include "libpandafile/type_helper.h"
54 
55 namespace panda {
56 
Proto(const panda_file::File & pf,panda_file::File::EntityId proto_id)57 Method::Proto::Proto(const panda_file::File &pf, panda_file::File::EntityId proto_id)
58 {
59     panda_file::ProtoDataAccessor pda(pf, proto_id);
60 
61     pda.EnumerateTypes([this](panda_file::Type type) { shorty_.push_back(type); });
62 
63     auto ref_num = pda.GetRefNum();
64     for (size_t ref_idx = 0; ref_idx < ref_num; ++ref_idx) {
65         auto id = pda.GetReferenceType(ref_idx);
66         ref_types_.emplace_back(utf::Mutf8AsCString(pf.GetStringData(id).data));
67     }
68 }
69 
operator ==(const Method::ProtoId & other) const70 bool Method::ProtoId::operator==(const Method::ProtoId &other) const
71 {
72     if (&pf_ == &other.pf_) {
73         return proto_id_ == other.proto_id_;
74     }
75 
76     panda_file::ProtoDataAccessor pda1(pf_, proto_id_);
77     panda_file::ProtoDataAccessor pda2(other.pf_, other.proto_id_);
78     return pda1.IsEqual(&pda2);
79 }
80 
operator ==(const Proto & other) const81 bool Method::ProtoId::operator==(const Proto &other) const
82 {
83     const auto &shorties = other.GetShorty();
84     const auto &ref_types = other.GetRefTypes();
85 
86     bool equal = true;
87     size_t shorty_idx = 0;
88     panda_file::ProtoDataAccessor pda(pf_, proto_id_);
89     pda.EnumerateTypes([&equal, &shorties, &shorty_idx](panda_file::Type type) {
90         equal = equal && shorty_idx < shorties.size() && type == shorties[shorty_idx];
91         ++shorty_idx;
92     });
93     if (!equal || shorty_idx != shorties.size() || pda.GetRefNum() != ref_types.size()) {
94         return false;
95     }
96 
97     // check ref types
98     for (size_t ref_idx = 0; ref_idx < ref_types.size(); ++ref_idx) {
99         auto id = pda.GetReferenceType(ref_idx);
100         if (ref_types[ref_idx] != utf::Mutf8AsCString(pf_.GetStringData(id).data)) {
101             return false;
102         }
103     }
104 
105     return true;
106 }
107 
GetReturnTypeDescriptor() const108 std::string_view Method::Proto::GetReturnTypeDescriptor() const
109 {
110     auto ret_type = GetReturnType();
111     if (!ret_type.IsPrimitive()) {
112         return ref_types_[0];
113     }
114 
115     switch (ret_type.GetId()) {
116         case panda_file::Type::TypeId::VOID:
117             return "V";
118         case panda_file::Type::TypeId::U1:
119             return "Z";
120         case panda_file::Type::TypeId::I8:
121             return "B";
122         case panda_file::Type::TypeId::U8:
123             return "H";
124         case panda_file::Type::TypeId::I16:
125             return "S";
126         case panda_file::Type::TypeId::U16:
127             return "C";
128         case panda_file::Type::TypeId::I32:
129             return "I";
130         case panda_file::Type::TypeId::U32:
131             return "U";
132         case panda_file::Type::TypeId::F32:
133             return "F";
134         case panda_file::Type::TypeId::I64:
135             return "J";
136         case panda_file::Type::TypeId::U64:
137             return "Q";
138         case panda_file::Type::TypeId::F64:
139             return "D";
140         case panda_file::Type::TypeId::TAGGED:
141             return "A";
142         default:
143             UNREACHABLE();
144     }
145 }
146 
GetFullNameHashFromString(const PandaString & str)147 uint32_t Method::GetFullNameHashFromString(const PandaString &str)
148 {
149     return GetHash32String(reinterpret_cast<const uint8_t *>(str.c_str()));
150 }
151 
GetClassNameHashFromString(const PandaString & str)152 uint32_t Method::GetClassNameHashFromString(const PandaString &str)
153 {
154     return GetHash32String(reinterpret_cast<const uint8_t *>(str.c_str()));
155 }
156 
CalcUniqId(const uint8_t * class_descr,const uint8_t * name)157 Method::UniqId Method::CalcUniqId(const uint8_t *class_descr, const uint8_t *name)
158 {
159     auto constexpr HALF = 32ULL;
160     constexpr uint64_t NO_FILE = 0xFFFFFFFFULL << HALF;
161     uint64_t hash = PseudoFnvHashString(class_descr);
162     hash = PseudoFnvHashString(name, hash);
163     return NO_FILE | hash;
164 }
165 
Method(Class * klass,const panda_file::File * pf,panda_file::File::EntityId file_id,panda_file::File::EntityId code_id,uint32_t access_flags,uint32_t num_args,const uint16_t * shorty)166 Method::Method(Class *klass, const panda_file::File *pf, panda_file::File::EntityId file_id,
167                panda_file::File::EntityId code_id, uint32_t access_flags, uint32_t num_args, const uint16_t *shorty)
168     : access_flags_(access_flags),
169       num_args_(num_args),
170       stor_16_pair_({0, 0}),
171       class_word_(static_cast<ClassHelper::classWordSize>(ToObjPtrType(klass))),
172       compiled_entry_point_(nullptr),
173       panda_file_(pf),
174       pointer_(),
175 
176       file_id_(file_id),
177       code_id_(code_id),
178       shorty_(shorty)
179 {
180     // Atomic with relaxed order reason: data race with native_pointer_ with no synchronization or ordering constraints
181     // imposed on other reads or writes NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
182     pointer_.native_pointer_.store(nullptr, std::memory_order_relaxed);
183     SetCompilationStatus(CompilationStage::NOT_COMPILED);
184 }
185 
Invoke(ManagedThread * thread,Value * args,bool proxy_call)186 Value Method::Invoke(ManagedThread *thread, Value *args, bool proxy_call)
187 {
188     ASSERT(!thread->HasPendingException());
189     return InvokeImpl<InvokeHelperStatic>(thread, GetNumArgs(), args, proxy_call);
190 }
191 
GetReturnType() const192 panda_file::Type Method::GetReturnType() const
193 {
194     panda_file::ShortyIterator it(shorty_);
195     return *it;
196 }
197 
GetArgType(size_t idx) const198 panda_file::Type Method::GetArgType(size_t idx) const
199 {
200     if (!IsStatic()) {
201         if (idx == 0) {
202             return panda_file::Type(panda_file::Type::TypeId::REFERENCE);
203         }
204 
205         --idx;
206     }
207 
208     panda_file::ProtoDataAccessor pda(*(panda_file_),
209                                       panda_file::MethodDataAccessor::GetProtoId(*(panda_file_), file_id_));
210     return pda.GetArgType(idx);
211 }
212 
GetRefReturnType() const213 panda_file::File::StringData Method::GetRefReturnType() const
214 {
215     ASSERT(GetReturnType().IsReference());
216     panda_file::ProtoDataAccessor pda(*(panda_file_),
217                                       panda_file::MethodDataAccessor::GetProtoId(*(panda_file_), file_id_));
218     panda_file::File::EntityId class_id = pda.GetReferenceType(0);
219     return panda_file_->GetStringData(class_id);
220 }
221 
GetRefArgType(size_t idx) const222 panda_file::File::StringData Method::GetRefArgType(size_t idx) const
223 {
224     if (!IsStatic()) {
225         if (idx == 0) {
226             return panda_file_->GetStringData(panda_file::MethodDataAccessor::GetClassId(*(panda_file_), file_id_));
227         }
228 
229         --idx;
230     }
231 
232     // in case of reference return type first idx corresponds to it
233     if (GetReturnType().IsReference()) {
234         ++idx;
235     }
236     panda_file::ProtoDataAccessor pda(*(panda_file_),
237                                       panda_file::MethodDataAccessor::GetProtoId(*(panda_file_), file_id_));
238     panda_file::File::EntityId class_id = pda.GetReferenceType(idx);
239     return panda_file_->GetStringData(class_id);
240 }
241 
GetName() const242 panda_file::File::StringData Method::GetName() const
243 {
244     return panda_file::MethodDataAccessor::GetName(*(panda_file_), file_id_);
245 }
246 
GetFullName(bool with_signature) const247 PandaString Method::GetFullName(bool with_signature) const
248 {
249     PandaOStringStream ss;
250     int ref_idx = 0;
251     if (with_signature) {
252         auto return_type = GetReturnType();
253         if (return_type.IsReference()) {
254             ss << ClassHelper::GetName(GetRefReturnType().data) << ' ';
255         } else {
256             ss << return_type << ' ';
257         }
258     }
259     if (GetClass() != nullptr) {
260         ss << PandaString(GetClass()->GetName());
261     }
262     ss << "::" << utf::Mutf8AsCString(Method::GetName().data);
263     if (!with_signature) {
264         return ss.str();
265     }
266     const char *sep = "";
267     ss << '(';
268     panda_file::ProtoDataAccessor pda(*(panda_file_),
269                                       panda_file::MethodDataAccessor::GetProtoId(*(panda_file_), file_id_));
270     for (size_t i = 0; i < GetNumArgs(); i++) {
271         auto type = GetEffectiveArgType(i);
272         if (type.IsReference()) {
273             ss << sep << ClassHelper::GetName(GetRefArgType(ref_idx++).data);
274         } else {
275             ss << sep << type;
276         }
277         sep = ", ";
278     }
279     ss << ')';
280     return ss.str();
281 }
282 
GetClassName() const283 panda_file::File::StringData Method::GetClassName() const
284 {
285     return panda_file_->GetStringData(panda_file::MethodDataAccessor::GetClassId(*(panda_file_), file_id_));
286 }
287 
GetProto() const288 Method::Proto Method::GetProto() const
289 {
290     return Proto(*(panda_file_), panda_file::MethodDataAccessor::GetProtoId(*(panda_file_), file_id_));
291 }
292 
GetProtoId() const293 Method::ProtoId Method::GetProtoId() const
294 {
295     return ProtoId(*(panda_file_), panda_file::MethodDataAccessor::GetProtoId(*(panda_file_), file_id_));
296 }
297 
GetNumericalAnnotation(AnnotationField field_id) const298 uint32_t Method::GetNumericalAnnotation(AnnotationField field_id) const
299 {
300     panda_file::MethodDataAccessor mda(*(panda_file_), file_id_);
301     return mda.GetNumericalAnnotation(field_id);
302 }
303 
GetStringDataAnnotation(AnnotationField field_id) const304 panda_file::File::StringData Method::GetStringDataAnnotation(AnnotationField field_id) const
305 {
306     ASSERT(field_id >= AnnotationField::STRING_DATA_BEGIN && field_id <= AnnotationField::STRING_DATA_END);
307     panda_file::MethodDataAccessor mda(*(panda_file_), file_id_);
308     uint32_t str_offset = mda.GetNumericalAnnotation(field_id);
309     if (str_offset == 0) {
310         return {0, nullptr};
311     }
312     return panda_file_->GetStringData(panda_file::File::EntityId(str_offset));
313 }
314 
GetBranchTakenCounter(uint32_t pc)315 int64_t Method::GetBranchTakenCounter(uint32_t pc)
316 {
317     auto profiling_data = GetProfilingData();
318     if (profiling_data == nullptr) {
319         return 0;
320     }
321     return profiling_data->GetBranchTakenCounter(pc);
322 }
323 
GetBranchNotTakenCounter(uint32_t pc)324 int64_t Method::GetBranchNotTakenCounter(uint32_t pc)
325 {
326     auto profiling_data = GetProfilingData();
327     if (profiling_data == nullptr) {
328         return 0;
329     }
330     return profiling_data->GetBranchNotTakenCounter(pc);
331 }
332 
FindCatchBlock(const Class * cls,uint32_t pc) const333 uint32_t Method::FindCatchBlock(const Class *cls, uint32_t pc) const
334 {
335     ASSERT(!IsAbstract());
336 
337     auto *thread = ManagedThread::GetCurrent();
338     [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
339     VMHandle<ObjectHeader> exception(thread, thread->GetException());
340     thread->ClearException();
341 
342     panda_file::MethodDataAccessor mda(*(panda_file_), file_id_);
343     panda_file::CodeDataAccessor cda(*(panda_file_), mda.GetCodeId().value());
344 
345     uint32_t pc_offset = panda_file::INVALID_OFFSET;
346 
347     cda.EnumerateTryBlocks([&pc_offset, cls, pc, this](panda_file::CodeDataAccessor::TryBlock &try_block) {
348         if ((try_block.GetStartPc() <= pc) && ((try_block.GetStartPc() + try_block.GetLength()) > pc)) {
349             try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) {
350                 auto type_idx = catch_block.GetTypeIdx();
351                 if (type_idx == panda_file::INVALID_INDEX) {
352                     pc_offset = catch_block.GetHandlerPc();
353                     return false;
354                 }
355 
356                 auto type_id = GetClass()->ResolveClassIndex(type_idx);
357                 auto *handler_class = Runtime::GetCurrent()->GetClassLinker()->GetClass(*this, type_id);
358                 if (cls->IsSubClassOf(handler_class)) {
359                     pc_offset = catch_block.GetHandlerPc();
360                     return false;
361                 }
362                 return true;
363             });
364         }
365         return pc_offset == panda_file::INVALID_OFFSET;
366     });
367 
368     thread->SetException(exception.GetPtr());
369 
370     return pc_offset;
371 }
372 
GetEffectiveArgType(size_t idx) const373 panda_file::Type Method::GetEffectiveArgType(size_t idx) const
374 {
375     return panda_file::GetEffectiveType(GetArgType(idx));
376 }
377 
GetEffectiveReturnType() const378 panda_file::Type Method::GetEffectiveReturnType() const
379 {
380     return panda_file::GetEffectiveType(GetReturnType());
381 }
382 
GetLineNumFromBytecodeOffset(uint32_t bc_offset) const383 int32_t Method::GetLineNumFromBytecodeOffset(uint32_t bc_offset) const
384 {
385     panda_file::MethodDataAccessor mda(*(panda_file_), file_id_);
386     return panda_file::debug_helpers::GetLineNumber(mda, bc_offset, panda_file_);
387 }
388 
GetClassSourceFile() const389 panda_file::File::StringData Method::GetClassSourceFile() const
390 {
391     panda_file::ClassDataAccessor cda(*(panda_file_), GetClass()->GetFileId());
392     auto source_file_id = cda.GetSourceFileId();
393     if (!source_file_id) {
394         return {0, nullptr};
395     }
396 
397     return panda_file_->GetStringData(source_file_id.value());
398 }
399 
IsVerified() const400 bool Method::IsVerified() const
401 {
402     if (IsIntrinsic()) {
403         return true;
404     }
405     auto stage = GetVerificationStage();
406     return stage == VerificationStage::VERIFIED_OK || stage == VerificationStage::VERIFIED_FAIL;
407 }
408 
WaitForVerification()409 void Method::WaitForVerification()
410 {
411     if (GetVerificationStage() == VerificationStage::WAITING) {
412         LOG(DEBUG, VERIFIER) << "Method '" << GetFullName() << std::hex << "' is waiting to be verified";
413         panda::verifier::ThreadPool::WaitForVerification(
414             [this] { return GetVerificationStage() == VerificationStage::WAITING; },
415             [this] { SetVerificationStage(VerificationStage::VERIFIED_FAIL); });
416     }
417 }
418 
SetVerified(bool result)419 void Method::SetVerified(bool result)
420 {
421     if (IsIntrinsic()) {
422         return;
423     }
424     verifier::VerificationResultCache::CacheResult(GetUniqId(), result);
425     SetVerificationStage(result ? VerificationStage::VERIFIED_OK : VerificationStage::VERIFIED_FAIL);
426     panda::verifier::ThreadPool::SignalMethodVerified();
427 }
428 
Verify()429 bool Method::Verify()
430 {
431     if (IsIntrinsic()) {
432         return true;
433     }
434     auto stage = GetVerificationStage();
435     if (stage == VerificationStage::VERIFIED_OK) {
436         return true;
437     }
438     if (stage == VerificationStage::VERIFIED_FAIL) {
439         return false;
440     }
441 
442     EnqueueForVerification();
443     WaitForVerification();
444 
445     return Verify();
446 }
447 
~Method()448 Method::~Method()
449 {
450     WaitForVerification();
451 }
452 
AddJobInQueue()453 bool Method::AddJobInQueue()
454 {
455     if (code_id_.IsValid() && !verifier::debug::SkipVerification(GetUniqId())) {
456         if (ExchangeVerificationStage(VerificationStage::WAITING) == VerificationStage::WAITING) {
457             return true;
458         }
459         if (verifier::VerificationResultCache::Enabled()) {
460             auto status = verifier::VerificationResultCache::Check(GetUniqId());
461             switch (status) {
462                 case verifier::VerificationResultCache::Status::OK:
463                     SetVerificationStage(VerificationStage::VERIFIED_OK);
464                     LOG(DEBUG, VERIFIER) << "Verification result of method '" << GetFullName() << "' was cached: OK";
465                     return true;
466                 case verifier::VerificationResultCache::Status::FAILED:
467                     SetVerificationStage(VerificationStage::VERIFIED_FAIL);
468                     LOG(DEBUG, VERIFIER) << "Verification result of method '" << GetFullName() << "' was cached: FAIL";
469                     return true;
470                 default:
471                     break;
472             }
473         }
474         if (panda::verifier::ThreadPool::Enqueue(this)) {
475             LOG(DEBUG, VERIFIER) << "Method '" << GetFullName() << "' enqueued for verification";
476         } else {
477             LOG(WARNING, VERIFIER) << "Method '" << GetFullName() << "' cannot be enqueued for verification";
478             SetVerificationStage(VerificationStage::VERIFIED_FAIL);
479         }
480         return true;
481     }
482 
483     return false;
484 }
485 
EnqueueForVerification()486 void Method::EnqueueForVerification()
487 {
488     if (IsIntrinsic()) {
489         LOG(DEBUG, VERIFIER) << "Intrinsic method " << GetFullName(true) << " doesn't need to be verified";
490         return;
491     }
492     if (GetVerificationStage() != VerificationStage::NOT_VERIFIED) {
493         LOG(DEBUG, VERIFIER) << "Method " << GetFullName(true) << " is already verified";
494         return;
495     }
496     auto &&verif_options = Runtime::GetCurrent()->GetVerificationOptions();
497     if (verif_options.IsEnabled()) {
498         verifier::debug::DebugContext::GetCurrent().AddMethod(*this, verif_options.Mode == VerificationMode::DEBUG);
499 
500         bool is_system = false;
501         if (!verif_options.VerifyRuntimeLibraries) {
502             auto *klass = GetClass();
503             if (klass != nullptr) {
504                 is_system = verifier::IsSystemClass(*klass);
505             }
506         }
507         if (is_system) {
508             LOG(DEBUG, VERIFIER) << "Skipping verification of system method " << GetFullName(true);
509         } else if (AddJobInQueue()) {
510             return;
511         }
512     }
513     if (verif_options.Show.Status) {
514         LOG(DEBUG, VERIFIER) << "Verification result of method '" << GetFullName(true) << "': SKIP";
515     }
516     SetVerified(true);
517 }
518 
GetVerificationStage() const519 Method::VerificationStage Method::GetVerificationStage() const
520 {
521     // Atomic with acquire order reason: data race with access_flags_ with dependecies on reads after the load which
522     // should become visible
523     return BitsToVerificationStage(access_flags_.load(std::memory_order_acquire));
524 }
525 
SetVerificationStage(VerificationStage stage)526 void Method::SetVerificationStage(VerificationStage stage)
527 {
528     // Atomic with acq_rel order reason: data race with access_flags_ with dependecies on reads after the load and on
529     // writes before the store
530     access_flags_.fetch_or((static_cast<uint32_t>(stage) << VERIFICATION_STATUS_SHIFT), std::memory_order_acq_rel);
531 }
532 
ExchangeVerificationStage(VerificationStage stage)533 Method::VerificationStage Method::ExchangeVerificationStage(VerificationStage stage)
534 {
535     // Atomic with acq_rel order reason: data race with access_flags_ with dependecies on reads after the load and on
536     // writes before the store
537     return BitsToVerificationStage(
538         access_flags_.fetch_or((static_cast<uint32_t>(stage) << VERIFICATION_STATUS_SHIFT), std::memory_order_acq_rel));
539 }
540 
BitsToVerificationStage(uint32_t bits)541 Method::VerificationStage Method::BitsToVerificationStage(uint32_t bits)
542 {
543     uint32_t val = (bits & VERIFICATION_STATUS_MASK) >> VERIFICATION_STATUS_SHIFT;
544     // To avoid if - else for conversion set bit index to VerificationStage
545     // y = 4x / 3 function for integers is used. It produces correct values for
546     // all correct inputs:
547     //                state  value __builtin_ffs 4x/3 VerificationStage
548     //         not verified:  000        0        0     NOT_VERIFIED
549     //              waiting:  100        3        3     WAITING
550     // verification success:  110        2        2     VERIFIED_OK
551     //  verification failed:  101        1        1     VERIFIED_FAIL
552     return static_cast<VerificationStage>(4U * panda_bit_utils_ffs(val) / 3U);
553 }
554 
StartProfiling()555 void Method::StartProfiling()
556 {
557 #ifdef PANDA_WITH_ECMASCRIPT
558     // Object handles can be created during class initialization, so check lock state only after GC is started.
559     ASSERT(!ManagedThread::GetCurrent()->GetVM()->GetGC()->IsGCRunning() || Locks::mutator_lock->HasLock() ||
560            ManagedThread::GetCurrent()->GetThreadLang() == panda::panda_file::SourceLang::ECMASCRIPT);
561 #else
562     ASSERT(!ManagedThread::GetCurrent()->GetVM()->GetGC()->IsGCRunning() || Locks::mutator_lock->HasLock());
563 #endif
564 
565     // Some thread already started profiling
566     if (IsProfilingWithoutLock()) {
567         return;
568     }
569 
570     mem::InternalAllocatorPtr allocator = Runtime::GetCurrent()->GetInternalAllocator();
571     PandaVector<uint32_t> vcalls;
572     PandaVector<uint32_t> branches;
573 
574     Span<const uint8_t> instructions(GetInstructions(), GetCodeSize());
575     for (BytecodeInstruction inst(instructions.begin()); inst.GetAddress() < instructions.end();
576          inst = inst.GetNext()) {
577         if (inst.HasFlag(BytecodeInstruction::Flags::CALL_VIRT)) {
578             vcalls.push_back(inst.GetAddress() - GetInstructions());
579         }
580         if (inst.HasFlag(BytecodeInstruction::Flags::JUMP)) {
581             branches.push_back(inst.GetAddress() - GetInstructions());
582         }
583     }
584     if (vcalls.empty() && branches.empty()) {
585         return;
586     }
587     ASSERT(std::is_sorted(vcalls.begin(), vcalls.end()));
588 
589     auto data = allocator->Alloc(RoundUp(RoundUp(sizeof(ProfilingData), alignof(CallSiteInlineCache)) +
590                                              sizeof(CallSiteInlineCache) * vcalls.size(),
591                                          alignof(BranchData)) +
592                                  sizeof(BranchData) * branches.size());
593     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
594     auto vcalls_mem = reinterpret_cast<uint8_t *>(data) + RoundUp(sizeof(ProfilingData), alignof(CallSiteInlineCache));
595     auto branches_data_offset = RoundUp(RoundUp(sizeof(ProfilingData), alignof(CallSiteInlineCache)) +
596                                             sizeof(CallSiteInlineCache) * vcalls.size(),
597                                         alignof(BranchData));
598     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
599     auto branches_mem = reinterpret_cast<uint8_t *>(data) + branches_data_offset;
600     auto profiling_data = new (data)
601         ProfilingData(CallSiteInlineCache::From(vcalls_mem, vcalls), BranchData::From(branches_mem, branches));
602 
603     ProfilingData *old_value = nullptr;
604     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
605     while (!pointer_.profiling_data_.compare_exchange_weak(old_value, profiling_data)) {
606         if (old_value != nullptr) {
607             // We're late, some thread already started profiling.
608             allocator->Delete(data);
609             return;
610         }
611     }
612     EVENT_INTERP_PROFILING(events::InterpProfilingAction::START, GetFullName(), vcalls.size());
613 }
614 
StopProfiling()615 void Method::StopProfiling()
616 {
617     ASSERT(!ManagedThread::GetCurrent()->GetVM()->GetGC()->IsGCRunning() || Locks::mutator_lock->HasLock());
618 
619     if (!IsProfilingWithoutLock()) {
620         return;
621     }
622 
623     EVENT_INTERP_PROFILING(events::InterpProfilingAction::STOP, GetFullName(),
624                            GetProfilingData()->GetInlineCaches().size());
625 
626     mem::InternalAllocatorPtr allocator = Runtime::GetCurrent()->GetInternalAllocator();
627     allocator->Free(GetProfilingData());
628     // Atomic with release order reason: data race with profiling_data_ with dependecies on writes before the store
629     // which should become visible acquire NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access)
630     pointer_.profiling_data_.store(nullptr, std::memory_order_release);
631 }
632 
IsProxy() const633 bool Method::IsProxy() const
634 {
635     return GetClass()->IsProxy();
636 }
637 
638 }  // namespace panda
639