• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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