1 /*
2 * Copyright (c) 2021 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/debug/config_load.h"
17 #include "verification/debug/allowlist/allowlist.h"
18 #include "verification/job_queue/job_queue.h"
19 #include "verification/job_queue/job_fill.h"
20 #include "verification/cache/results_cache.h"
21 #include "verification/util/invalid_ref.h"
22
23 #include "events/events.h"
24 #include "runtime/bridge/bridge.h"
25 #include "runtime/entrypoints/entrypoints.h"
26 #include "runtime/jit/profiling_data.h"
27 #include "runtime/include/class_linker-inl.h"
28 #include "runtime/include/exceptions.h"
29 #include "runtime/include/locks.h"
30 #include "runtime/include/mem/panda_smart_pointers.h"
31 #include "runtime/include/method-inl.h"
32 #include "runtime/include/runtime.h"
33 #include "runtime/include/panda_vm.h"
34 #include "runtime/include/runtime_notification.h"
35 #include "runtime/include/value-inl.h"
36 #include "runtime/interpreter/frame.h"
37 #include "runtime/interpreter/interpreter.h"
38 #include "libpandabase/utils/hash.h"
39 #include "libpandabase/utils/span.h"
40 #include "libpandabase/utils/utf.h"
41 #include "libpandabase/os/mutex.h"
42 #include "libpandafile/code_data_accessor-inl.h"
43 #include "libpandafile/debug_data_accessor-inl.h"
44 #include "libpandafile/file-inl.h"
45 #include "libpandafile/line_program_state.h"
46 #include "libpandafile/method_data_accessor-inl.h"
47 #include "libpandafile/method_data_accessor.h"
48 #include "libpandafile/proto_data_accessor-inl.h"
49 #include "libpandafile/shorty_iterator.h"
50 #include "runtime/handle_base-inl.h"
51 #include "runtime/handle_scope-inl.h"
52 #include "libpandafile/type_helper.h"
53
54 namespace panda {
55
Proto(const panda_file::File & pf,panda_file::File::EntityId proto_id)56 Method::Proto::Proto(const panda_file::File &pf, panda_file::File::EntityId proto_id)
57 {
58 panda_file::ProtoDataAccessor pda(pf, proto_id);
59
60 pda.EnumerateTypes([this](panda_file::Type type) { shorty_.push_back(type); });
61
62 size_t ref_idx = 0;
63
64 for (auto &t : shorty_) {
65 if (t.IsPrimitive()) {
66 continue;
67 }
68
69 auto id = pda.GetReferenceType(ref_idx++);
70 ref_types_.emplace_back(utf::Mutf8AsCString(pf.GetStringData(id).data));
71 }
72 }
73
GetReturnTypeDescriptor() const74 std::string_view Method::Proto::GetReturnTypeDescriptor() const
75 {
76 auto ret_type = GetReturnType();
77 if (!ret_type.IsPrimitive()) {
78 return ref_types_[0];
79 }
80
81 switch (ret_type.GetId()) {
82 case panda_file::Type::TypeId::VOID:
83 return "V";
84 case panda_file::Type::TypeId::U1:
85 return "Z";
86 case panda_file::Type::TypeId::I8:
87 return "B";
88 case panda_file::Type::TypeId::U8:
89 return "H";
90 case panda_file::Type::TypeId::I16:
91 return "S";
92 case panda_file::Type::TypeId::U16:
93 return "C";
94 case panda_file::Type::TypeId::I32:
95 return "I";
96 case panda_file::Type::TypeId::U32:
97 return "U";
98 case panda_file::Type::TypeId::F32:
99 return "F";
100 case panda_file::Type::TypeId::I64:
101 return "J";
102 case panda_file::Type::TypeId::U64:
103 return "Q";
104 case panda_file::Type::TypeId::F64:
105 return "D";
106 case panda_file::Type::TypeId::TAGGED:
107 return "A";
108 default:
109 UNREACHABLE();
110 }
111 }
112
GetFullNameHashFromString(const uint8_t * str)113 uint32_t Method::GetFullNameHashFromString(const uint8_t *str)
114 {
115 return GetHash32String(str);
116 }
117
GetClassNameHashFromString(const uint8_t * str)118 uint32_t Method::GetClassNameHashFromString(const uint8_t *str)
119 {
120 return GetHash32String(str);
121 }
122
GetFullNameHash() const123 uint32_t Method::GetFullNameHash() const
124 {
125 // NB: this function cannot be used in current unit tests, because
126 // some unit tests are using underdefined method objects
127 ASSERT(panda_file_ != nullptr && file_id_.IsValid());
128 PandaString full_name {ClassHelper::GetName(GetClassName().data)};
129 full_name += "::";
130 full_name += utf::Mutf8AsCString(GetName().data);
131 auto hash = GetFullNameHashFromString(reinterpret_cast<const uint8_t *>(full_name.c_str()));
132 return hash;
133 }
134
CalcUniqId(const uint8_t * class_descr,const uint8_t * name)135 Method::UniqId Method::CalcUniqId(const uint8_t *class_descr, const uint8_t *name)
136 {
137 auto constexpr HALF = 32ULL;
138 constexpr uint64_t NO_FILE = 0xFFFFFFFFULL << HALF;
139 uint64_t hash = PseudoFnvHashString(class_descr);
140 hash = PseudoFnvHashString(name, hash);
141 return NO_FILE | hash;
142 }
143
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)144 Method::Method(Class *klass, const panda_file::File *pf, panda_file::File::EntityId file_id,
145 panda_file::File::EntityId code_id, uint32_t access_flags, uint32_t num_args, const uint16_t *shorty)
146 : stor_32_ {{}, access_flags, 0, num_args, 0},
147 stor_ptr_ {{}, klass, nullptr, nullptr},
148 panda_file_(pf),
149 file_id_(file_id),
150 code_id_(code_id),
151 shorty_(shorty)
152 {
153 SetCompilationStatus(CompilationStage::NOT_COMPILED);
154 }
155
Invoke(ManagedThread * thread,Value * args,bool proxy_call)156 Value Method::Invoke(ManagedThread *thread, Value *args, bool proxy_call)
157 {
158 return InvokeImpl<false>(thread, GetNumArgs(), args, proxy_call);
159 }
160
InvokeDyn(ManagedThread * thread,uint32_t num_args,Value * args,bool proxy_call,void * data)161 Value Method::InvokeDyn(ManagedThread *thread, uint32_t num_args, Value *args, bool proxy_call, void *data)
162 {
163 return InvokeImpl<true>(thread, num_args, args, proxy_call, data);
164 }
165
InvokeGen(ManagedThread * thread,const uint8_t * pc,Value acc,uint32_t num_actual_args,Value * args,void * data)166 Value Method::InvokeGen(ManagedThread *thread, const uint8_t *pc, Value acc, uint32_t num_actual_args, Value *args,
167 void *data)
168 {
169 Frame *current_frame = thread->GetCurrentFrame();
170 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_REDUNDANT_INIT)
171 Value res(static_cast<int64_t>(0));
172 panda_file::Type ret_type = GetReturnType();
173 if (!Verify()) {
174 auto ctx = Runtime::GetCurrent()->GetLanguageContext(*this);
175 panda::ThrowVerificationException(ctx, GetFullName());
176 if (ret_type.IsReference()) {
177 res = Value(nullptr);
178 } else {
179 res = Value(static_cast<int64_t>(0));
180 }
181 } else {
182 Span<Value> args_span(args, num_actual_args);
183 auto frame_deleter = [](Frame *frame) { FreeFrame(frame); };
184 PandaUniquePtr<Frame, FrameDeleter> frame(
185 CreateFrameWithActualArgs(num_actual_args, num_actual_args, this, current_frame), frame_deleter);
186
187 for (size_t i = 0; i < num_actual_args; i++) {
188 if (args_span[i].IsDecodedTaggedValue()) {
189 DecodedTaggedValue decoded = args_span[i].GetDecodedTaggedValue();
190 frame->GetVReg(i).SetValue(decoded.value);
191 frame->GetVReg(i).SetTag(decoded.tag);
192 } else if (args_span[i].IsReference()) {
193 frame->GetVReg(i).SetReference(args_span[i].GetAs<ObjectHeader *>());
194 } else {
195 frame->GetVReg(i).SetPrimitive(args_span[i].GetAs<int64_t>());
196 }
197 }
198 frame->GetAcc().SetValue(static_cast<uint64_t>(acc.GetAs<int64_t>()));
199 frame->SetData(data);
200
201 if (UNLIKELY(frame.get() == nullptr)) {
202 panda::ThrowOutOfMemoryError("CreateFrame failed: " + GetFullName());
203 if (ret_type.IsReference()) {
204 res = Value(nullptr);
205 } else {
206 res = Value(static_cast<int64_t>(0));
207 }
208 return res;
209 }
210 thread->SetCurrentFrame(frame.get());
211
212 Runtime::GetCurrent()->GetNotificationManager()->MethodEntryEvent(thread, this);
213 interpreter::Execute(thread, pc, frame.get());
214 Runtime::GetCurrent()->GetNotificationManager()->MethodExitEvent(thread, this);
215
216 thread->SetCurrentFrame(current_frame);
217 res = GetReturnValueFromAcc(ret_type, thread->HasPendingException(), frame->GetAcc());
218 }
219 return res;
220 }
221
GetReturnType() const222 panda_file::Type Method::GetReturnType() const
223 {
224 panda_file::ShortyIterator it(shorty_);
225 return *it;
226 }
227
GetArgType(size_t idx) const228 panda_file::Type Method::GetArgType(size_t idx) const
229 {
230 if (!IsStatic()) {
231 if (idx == 0) {
232 return panda_file::Type(panda_file::Type::TypeId::REFERENCE);
233 }
234
235 --idx;
236 }
237
238 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
239 panda_file::ProtoDataAccessor pda(*panda_file_, mda.GetProtoId());
240 return pda.GetArgType(idx);
241 }
242
GetRefArgType(size_t idx) const243 panda_file::File::StringData Method::GetRefArgType(size_t idx) const
244 {
245 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
246
247 if (!IsStatic()) {
248 if (idx == 0) {
249 return panda_file_->GetStringData(mda.GetClassId());
250 }
251
252 --idx;
253 }
254
255 panda_file::ProtoDataAccessor pda(*panda_file_, mda.GetProtoId());
256 panda_file::File::EntityId class_id = pda.GetReferenceType(idx);
257 return panda_file_->GetStringData(class_id);
258 }
259
GetName() const260 panda_file::File::StringData Method::GetName() const
261 {
262 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
263 return panda_file_->GetStringData(mda.GetNameId());
264 }
265
GetFullName(bool with_signature) const266 PandaString Method::GetFullName(bool with_signature) const
267 {
268 PandaOStringStream ss;
269 int ref_idx = 0;
270 if (with_signature) {
271 auto return_type = GetReturnType();
272 if (return_type.IsReference()) {
273 ss << ClassHelper::GetName(GetRefArgType(ref_idx++).data) << ' ';
274 } else {
275 ss << return_type << ' ';
276 }
277 }
278 ss << PandaString(GetClass()->GetName()) << "::" << utf::Mutf8AsCString(Method::GetName().data);
279 if (!with_signature) {
280 return ss.str();
281 }
282 const char *sep = "";
283 ss << '(';
284 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
285 panda_file::ProtoDataAccessor pda(*panda_file_, mda.GetProtoId());
286 for (size_t i = 0; i < GetNumArgs(); i++) {
287 auto type = GetEffectiveArgType(i);
288 if (type.IsReference()) {
289 ss << sep << ClassHelper::GetName(GetRefArgType(ref_idx++).data);
290 } else {
291 ss << sep << type;
292 }
293 sep = ", ";
294 }
295 ss << ')';
296 return ss.str();
297 }
298
GetClassName() const299 panda_file::File::StringData Method::GetClassName() const
300 {
301 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
302 return panda_file_->GetStringData(mda.GetClassId());
303 }
304
GetProto() const305 Method::Proto Method::GetProto() const
306 {
307 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
308 return Proto(*panda_file_, mda.GetProtoId());
309 }
310
GetNumericalAnnotation(AnnotationField field_id) const311 uint32_t Method::GetNumericalAnnotation(AnnotationField field_id) const
312 {
313 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
314 return mda.GetNumericalAnnotation(field_id);
315 }
316
GetStringDataAnnotation(AnnotationField field_id) const317 panda_file::File::StringData Method::GetStringDataAnnotation(AnnotationField field_id) const
318 {
319 ASSERT(field_id >= AnnotationField::STRING_DATA_BEGIN);
320 ASSERT(field_id <= AnnotationField::STRING_DATA_END);
321 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
322 uint32_t str_offset = mda.GetNumericalAnnotation(field_id);
323 if (str_offset == 0) {
324 return {0, nullptr};
325 }
326 return panda_file_->GetStringData(panda_file::File::EntityId(str_offset));
327 }
328
FindCatchBlock(Class * cls,uint32_t pc) const329 uint32_t Method::FindCatchBlock(Class *cls, uint32_t pc) const
330 {
331 ASSERT(!IsAbstract());
332
333 auto *thread = ManagedThread::GetCurrent();
334 [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread);
335 VMHandle<ObjectHeader> exception(thread, thread->GetException());
336 thread->ClearException();
337
338 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
339 panda_file::CodeDataAccessor cda(*panda_file_, mda.GetCodeId().value());
340
341 uint32_t pc_offset = panda_file::INVALID_OFFSET;
342
343 cda.EnumerateTryBlocks([&pc_offset, cls, pc, this](panda_file::CodeDataAccessor::TryBlock &try_block) {
344 if ((try_block.GetStartPc() <= pc) && ((try_block.GetStartPc() + try_block.GetLength()) > pc)) {
345 try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) {
346 auto type_idx = catch_block.GetTypeIdx();
347 if (type_idx == panda_file::INVALID_INDEX) {
348 pc_offset = catch_block.GetHandlerPc();
349 return false;
350 }
351
352 auto type_id = GetClass()->ResolveClassIndex(type_idx);
353 auto *handler_class = Runtime::GetCurrent()->GetClassLinker()->GetClass(*this, type_id);
354 if (cls->IsSubClassOf(handler_class)) {
355 pc_offset = catch_block.GetHandlerPc();
356 return false;
357 }
358 return true;
359 });
360 }
361 return pc_offset == panda_file::INVALID_OFFSET;
362 });
363
364 thread->SetException(exception.GetPtr());
365
366 return pc_offset;
367 }
368
GetEffectiveArgType(size_t idx) const369 panda_file::Type Method::GetEffectiveArgType(size_t idx) const
370 {
371 return panda_file::GetEffectiveType(GetArgType(idx));
372 }
373
GetEffectiveReturnType() const374 panda_file::Type Method::GetEffectiveReturnType() const
375 {
376 return panda_file::GetEffectiveType(GetReturnType());
377 }
378
GetLineNumFromBytecodeOffset(uint32_t bc_offset) const379 int32_t Method::GetLineNumFromBytecodeOffset(uint32_t bc_offset) const
380 {
381 panda_file::MethodDataAccessor mda(*panda_file_, file_id_);
382 auto debug_info_id = mda.GetDebugInfoId();
383 if (!debug_info_id) {
384 return -1;
385 }
386
387 using Opcode = panda_file::LineNumberProgramItem::Opcode;
388 using EntityId = panda_file::File::EntityId;
389
390 panda_file::DebugInfoDataAccessor dda(*panda_file_, debug_info_id.value());
391 const uint8_t *program = dda.GetLineNumberProgram();
392 auto size = panda_file_->GetSpanFromId(panda_file_->GetIdFromPointer(program)).size();
393 auto opcode_sp = Span(reinterpret_cast<const Opcode *>(program), size);
394
395 panda_file::LineProgramState state(*panda_file_, EntityId(0), dda.GetLineStart(), dda.GetConstantPool());
396
397 size_t i = 0;
398 Opcode opcode;
399 size_t prev_line = state.GetLine();
400 while ((opcode = opcode_sp[i++]) != Opcode::END_SEQUENCE) {
401 switch (opcode) {
402 case Opcode::ADVANCE_LINE: {
403 auto line_diff = state.ReadSLeb128();
404 state.AdvanceLine(line_diff);
405 break;
406 }
407 case Opcode::ADVANCE_PC: {
408 auto pc_diff = state.ReadULeb128();
409 state.AdvancePc(pc_diff);
410 break;
411 }
412 default: {
413 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_REDUNDANT_INIT)
414 auto opcode_value = static_cast<uint8_t>(opcode);
415 if (opcode_value < panda_file::LineNumberProgramItem::OPCODE_BASE) {
416 break;
417 }
418
419 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_REDUNDANT_INIT)
420 auto adjust_opcode = opcode_value - panda_file::LineNumberProgramItem::OPCODE_BASE;
421 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_REDUNDANT_INIT)
422 uint32_t pc_diff = adjust_opcode / panda_file::LineNumberProgramItem::LINE_RANGE;
423 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_REDUNDANT_INIT)
424 int32_t line_diff = adjust_opcode % panda_file::LineNumberProgramItem::LINE_RANGE +
425 panda_file::LineNumberProgramItem::LINE_BASE;
426
427 state.AdvancePc(pc_diff);
428 state.AdvanceLine(line_diff);
429
430 if (state.GetAddress() == bc_offset) {
431 return state.GetLine();
432 }
433
434 if (state.GetAddress() > bc_offset) {
435 return prev_line;
436 }
437
438 prev_line = state.GetLine();
439
440 break;
441 }
442 }
443 }
444
445 return state.GetLine();
446 }
447
GetClassSourceFile() const448 panda_file::File::StringData Method::GetClassSourceFile() const
449 {
450 panda_file::ClassDataAccessor cda(*panda_file_, GetClass()->GetFileId());
451 auto source_file_id = cda.GetSourceFileId();
452 if (!source_file_id) {
453 return {0, nullptr};
454 }
455
456 return panda_file_->GetStringData(source_file_id.value());
457 }
458
IsVerified() const459 bool Method::IsVerified() const
460 {
461 if (IsIntrinsic()) {
462 return true;
463 }
464 auto stage = GetVerificationStage();
465 return stage == VerificationStage::VERIFIED_OK || stage == VerificationStage::VERIFIED_FAIL;
466 }
467
WaitForVerification()468 void Method::WaitForVerification()
469 {
470 if (GetVerificationStage() == VerificationStage::WAITING) {
471 LOG(DEBUG, VERIFIER) << "Method '" << GetFullName() << std::hex << "' ( 0x" << GetUniqId() << ", 0x"
472 << reinterpret_cast<uintptr_t>(this) << " ) is waiting to be verified";
473 panda::verifier::JobQueue::WaitForVerification(
474 [this] { return GetVerificationStage() == VerificationStage::WAITING; },
475 [this] {
476 auto &runtime = *Runtime::GetCurrent();
477 auto &&verif_options = runtime.GetVerificationOptions();
478 auto does_not_fail = verif_options.Mode.VerifierDoesNotFail;
479 SetVerificationStage(does_not_fail ? VerificationStage::VERIFIED_OK : VerificationStage::VERIFIED_FAIL);
480 });
481 }
482 }
483
SetVerified(bool result)484 void Method::SetVerified(bool result)
485 {
486 verifier::VerificationResultCache::CacheResult(GetUniqId(), result);
487 SetVerificationStage(result ? VerificationStage::VERIFIED_OK : VerificationStage::VERIFIED_FAIL);
488 panda::verifier::JobQueue::SignalMethodVerified();
489 }
490
Verify()491 bool Method::Verify()
492 {
493 if (IsIntrinsic()) {
494 return true;
495 }
496 auto stage = GetVerificationStage();
497 if (stage == VerificationStage::VERIFIED_OK) {
498 return true;
499 }
500 if (stage == VerificationStage::VERIFIED_FAIL) {
501 return false;
502 }
503
504 EnqueueForVerification();
505 auto &runtime = *Runtime::GetCurrent();
506 auto &&verif_options = runtime.GetVerificationOptions();
507 if (verif_options.Mode.VerifierDoesNotFail) {
508 return true;
509 }
510 WaitForVerification();
511
512 return Verify();
513 }
514
~Method()515 Method::~Method()
516 {
517 WaitForVerification();
518 }
519
AddJobInQueue()520 bool Method::AddJobInQueue()
521 {
522 if (code_id_.IsValid() && !SKIP_VERIFICATION(GetUniqId())) {
523 if (ExchangeVerificationStage(VerificationStage::WAITING) == VerificationStage::WAITING) {
524 return true;
525 }
526 if (verifier::VerificationResultCache::Enabled()) {
527 auto status = verifier::VerificationResultCache::Check(GetUniqId());
528 switch (status) {
529 case verifier::VerificationResultCache::Status::OK:
530 SetVerificationStage(VerificationStage::VERIFIED_OK);
531 LOG(INFO, VERIFIER) << "Verification result of method '" << GetFullName() << "' was cached: OK";
532 return true;
533 case verifier::VerificationResultCache::Status::FAILED:
534 SetVerificationStage(VerificationStage::VERIFIED_FAIL);
535 LOG(INFO, VERIFIER) << "Verification result of method '" << GetFullName() << "' was cached: FAIL";
536 return true;
537 default:
538 break;
539 }
540 }
541 auto &job = panda::verifier::JobQueue::NewJob(*this);
542 if (Invalid(job)) {
543 LOG(INFO, VERIFIER) << "Method '" << GetFullName()
544 << "' cannot be enqueued for verification. Cannot create job object.";
545 auto &runtime = *Runtime::GetCurrent();
546 auto &&verif_options = runtime.GetVerificationOptions();
547 auto does_not_fail = verif_options.Mode.VerifierDoesNotFail;
548 SetVerificationStage(does_not_fail ? VerificationStage::VERIFIED_OK : VerificationStage::VERIFIED_FAIL);
549 return true;
550 }
551 if (!panda::verifier::FillJob(job)) {
552 LOG(INFO, VERIFIER) << "Method '" << GetFullName() << "' cannot be enqueued for verification";
553 auto &runtime = *Runtime::GetCurrent();
554 auto &&verif_options = runtime.GetVerificationOptions();
555 auto does_not_fail = verif_options.Mode.VerifierDoesNotFail;
556 SetVerificationStage(does_not_fail ? VerificationStage::VERIFIED_OK : VerificationStage::VERIFIED_FAIL);
557 panda::verifier::JobQueue::DisposeJob(&job);
558 return true;
559 }
560 panda::verifier::JobQueue::AddJob(job);
561 LOG(INFO, VERIFIER) << "Method '" << GetFullName() << std::hex << "' ( 0x" << GetUniqId() << ", 0x"
562 << reinterpret_cast<uintptr_t>(this) << " ) enqueued for verification";
563 return true;
564 }
565
566 return false;
567 }
568
EnqueueForVerification()569 void Method::EnqueueForVerification()
570 {
571 if (GetVerificationStage() != VerificationStage::NOT_VERIFIED) {
572 return;
573 }
574 auto &runtime = *Runtime::GetCurrent();
575 auto &&verif_options = runtime.GetVerificationOptions();
576 if (verif_options.Enable) {
577 if (verif_options.Mode.DebugEnable) {
578 auto hash = GetFullNameHash();
579 PandaString class_name {ClassHelper::GetName(GetClassName().data)};
580 auto class_hash = GetFullNameHashFromString(reinterpret_cast<const uint8_t *>(class_name.c_str()));
581 panda::verifier::config::MethodIdCalculationHandler(class_hash, hash, GetUniqId());
582 }
583
584 bool is_system = false;
585 if (!verif_options.Mode.DoNotAssumeLibraryMethodsVerified) {
586 auto *klass = GetClass();
587 if (klass != nullptr) {
588 auto *file = klass->GetPandaFile();
589 is_system = file != nullptr && verifier::JobQueue::IsSystemFile(file);
590 }
591 }
592 if (!is_system && AddJobInQueue()) {
593 return;
594 }
595 }
596 if (verif_options.Show.Status) {
597 LOG(INFO, VERIFIER) << "Verification result of method '" << GetFullName() << "': SKIP";
598 }
599 SetVerified(true);
600 }
601
GetVerificationStage() const602 Method::VerificationStage Method::GetVerificationStage() const
603 {
604 return BitsToVerificationStage(stor_32_.access_flags_.load());
605 }
606
SetVerificationStage(VerificationStage stage)607 void Method::SetVerificationStage(VerificationStage stage)
608 {
609 stor_32_.access_flags_.fetch_or((static_cast<uint32_t>(stage) << VERIFICATION_STATUS_SHIFT));
610 }
611
ExchangeVerificationStage(VerificationStage stage)612 Method::VerificationStage Method::ExchangeVerificationStage(VerificationStage stage)
613 {
614 return BitsToVerificationStage(
615 stor_32_.access_flags_.fetch_or(static_cast<uint32_t>(stage) << VERIFICATION_STATUS_SHIFT));
616 }
617
BitsToVerificationStage(uint32_t bits)618 Method::VerificationStage Method::BitsToVerificationStage(uint32_t bits)
619 {
620 uint32_t val = (bits & VERIFICATION_STATUS_MASK) >> VERIFICATION_STATUS_SHIFT;
621 // To avoid if - else for conversion set bit index to VerificationStage
622 // y = 4x / 3 function for integers is used. It produces correct values for
623 // all correct inputs:
624 // state value __builtin_ffs 4x/3 VerificationStage
625 // not verified: 000 0 0 NOT_VERIFIED
626 // waiting: 100 3 3 WAITING
627 // verification success: 110 2 2 VERIFIED_OK
628 // verification failed: 101 1 1 VERIFIED_FAIL
629 return static_cast<VerificationStage>(4U * panda_bit_utils_ffs(val) / 3U);
630 }
631
StartProfiling()632 void Method::StartProfiling()
633 {
634 ASSERT(!ManagedThread::GetCurrent()->GetVM()->GetGC()->IsGCRunning() || Locks::mutator_lock->HasLock());
635
636 // Some thread already started profiling
637 if (IsProfilingWithoutLock()) {
638 return;
639 }
640
641 mem::InternalAllocatorPtr allocator = Runtime::GetCurrent()->GetInternalAllocator();
642 PandaVector<uint32_t> vcalls;
643
644 Span<const uint8_t> instructions(GetInstructions(), GetCodeSize());
645 for (BytecodeInstruction inst(instructions.begin()); inst.GetAddress() < instructions.end();
646 inst = inst.GetNext()) {
647 if (inst.HasFlag(BytecodeInstruction::Flags::CALL_VIRT)) {
648 vcalls.push_back(inst.GetAddress() - GetInstructions());
649 }
650 }
651 if (vcalls.empty()) {
652 return;
653 }
654 ASSERT(std::is_sorted(vcalls.begin(), vcalls.end()));
655
656 auto data = allocator->Alloc(RoundUp(sizeof(ProfilingData), alignof(CallSiteInlineCache)) +
657 sizeof(CallSiteInlineCache) * vcalls.size());
658 // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER)
659 auto profiling_data = new (data) ProfilingData(vcalls.size());
660
661 auto ics = profiling_data->GetInlineCaches();
662 for (size_t i = 0; i < vcalls.size(); i++) {
663 ics[i].Init(vcalls[i]);
664 }
665
666 ProfilingData *old_value = nullptr;
667 while (!profiling_data_.compare_exchange_weak(old_value, profiling_data)) {
668 if (old_value != nullptr) {
669 // We're late, some thread already started profiling.
670 allocator->Delete(data);
671 return;
672 }
673 }
674 EVENT_INTERP_PROFILING(events::InterpProfilingAction::START, GetFullName(), vcalls.size());
675 }
676
StopProfiling()677 void Method::StopProfiling()
678 {
679 ASSERT(!ManagedThread::GetCurrent()->GetVM()->GetGC()->IsGCRunning() || Locks::mutator_lock->HasLock());
680
681 if (!IsProfilingWithoutLock()) {
682 return;
683 }
684
685 EVENT_INTERP_PROFILING(events::InterpProfilingAction::STOP, GetFullName(),
686 GetProfilingData()->GetInlineCaches().size());
687
688 mem::InternalAllocatorPtr allocator = Runtime::GetCurrent()->GetInternalAllocator();
689 allocator->Free(GetProfilingData());
690 profiling_data_ = nullptr;
691 }
692
693 } // namespace panda
694