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