14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/method_literal.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/interpreter/interpreter.h" 194514f5e3Sopenharmony_ci#include "ecmascript/jspandafile/js_pandafile.h" 204514f5e3Sopenharmony_ci 214514f5e3Sopenharmony_ci#include "libpandafile/class_data_accessor.h" 224514f5e3Sopenharmony_ci#include "libpandafile/code_data_accessor-inl.h" 234514f5e3Sopenharmony_ci#include "libpandafile/method_data_accessor-inl.h" 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_cinamespace panda::ecmascript { 264514f5e3Sopenharmony_ciMethodLiteral::MethodLiteral(EntityId methodId) 274514f5e3Sopenharmony_ci{ 284514f5e3Sopenharmony_ci ASSERT(methodId.IsValid()); 294514f5e3Sopenharmony_ci SetMethodId(methodId); 304514f5e3Sopenharmony_ci} 314514f5e3Sopenharmony_ci 324514f5e3Sopenharmony_civoid MethodLiteral::Initialize(const JSPandaFile *jsPandaFile, const JSThread *thread) 334514f5e3Sopenharmony_ci{ 344514f5e3Sopenharmony_ci const panda_file::File *pf = jsPandaFile->GetPandaFile(); 354514f5e3Sopenharmony_ci EntityId methodId = GetMethodId(); 364514f5e3Sopenharmony_ci panda_file::MethodDataAccessor mda(*pf, methodId); 374514f5e3Sopenharmony_ci auto codeId = mda.GetCodeId().value(); 384514f5e3Sopenharmony_ci ASSERT(codeId.IsValid()); 394514f5e3Sopenharmony_ci 404514f5e3Sopenharmony_ci panda_file::CodeDataAccessor cda(*pf, codeId); 414514f5e3Sopenharmony_ci nativePointerOrBytecodeArray_ = cda.GetInstructions(); 424514f5e3Sopenharmony_ci uint32_t codeSize = cda.GetCodeSize(); 434514f5e3Sopenharmony_ci // When triggering jit compile through the execution count of the js function, set the hotness counter value to 0 444514f5e3Sopenharmony_ci // to ensure that the profile type info object can be created on the first execution of the js function. 454514f5e3Sopenharmony_ci bool cancelThreshold = (thread != nullptr && thread->GetEcmaVM()->GetJSOptions().GetJitCallThreshold() != 0); 464514f5e3Sopenharmony_ci SetHotnessCounter(EcmaInterpreter::GetHotnessCounter(codeSize, cancelThreshold)); 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_ci uint32_t callType = UINT32_MAX; // UINT32_MAX means not found 494514f5e3Sopenharmony_ci uint32_t slotSize = 0; 504514f5e3Sopenharmony_ci mda.EnumerateAnnotations([&](EntityId annotationId) { 514514f5e3Sopenharmony_ci panda_file::AnnotationDataAccessor ada(*pf, annotationId); 524514f5e3Sopenharmony_ci auto *annotationName = reinterpret_cast<const char *>(pf->GetStringData(ada.GetClassId()).data); 534514f5e3Sopenharmony_ci if (::strcmp("L_ESCallTypeAnnotation;", annotationName) == 0) { 544514f5e3Sopenharmony_ci uint32_t elemCount = ada.GetCount(); 554514f5e3Sopenharmony_ci for (uint32_t i = 0; i < elemCount; i++) { 564514f5e3Sopenharmony_ci panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i); 574514f5e3Sopenharmony_ci auto *elemName = reinterpret_cast<const char *>(pf->GetStringData(adae.GetNameId()).data); 584514f5e3Sopenharmony_ci if (::strcmp("callType", elemName) == 0) { 594514f5e3Sopenharmony_ci callType = adae.GetScalarValue().GetValue(); 604514f5e3Sopenharmony_ci } 614514f5e3Sopenharmony_ci } 624514f5e3Sopenharmony_ci } else if (::strcmp("L_ESSlotNumberAnnotation;", annotationName) == 0) { 634514f5e3Sopenharmony_ci uint32_t elemCount = ada.GetCount(); 644514f5e3Sopenharmony_ci for (uint32_t i = 0; i < elemCount; i++) { 654514f5e3Sopenharmony_ci panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i); 664514f5e3Sopenharmony_ci auto *elemName = reinterpret_cast<const char *>(pf->GetStringData(adae.GetNameId()).data); 674514f5e3Sopenharmony_ci if (::strcmp("SlotNumber", elemName) == 0) { 684514f5e3Sopenharmony_ci slotSize = adae.GetScalarValue().GetValue(); 694514f5e3Sopenharmony_ci } 704514f5e3Sopenharmony_ci } 714514f5e3Sopenharmony_ci } 724514f5e3Sopenharmony_ci }); 734514f5e3Sopenharmony_ci 744514f5e3Sopenharmony_ci uint32_t numVregs = cda.GetNumVregs(); 754514f5e3Sopenharmony_ci uint32_t numArgs = cda.GetNumArgs(); 764514f5e3Sopenharmony_ci ASSERT((numArgs - HaveFuncBit::Decode(callType) - 774514f5e3Sopenharmony_ci HaveNewTargetBit::Decode(callType) - HaveThisBit::Decode(callType)) >= 0); 784514f5e3Sopenharmony_ci // Needed info for call can be got by loading callField only once. 794514f5e3Sopenharmony_ci // Native bit will be set in NewMethodForNativeFunction(); 804514f5e3Sopenharmony_ci callField_ = (callType & CALL_TYPE_MASK) | 814514f5e3Sopenharmony_ci NumVregsBits::Encode(numVregs) | 824514f5e3Sopenharmony_ci NumArgsBits::Encode(numArgs - HaveFuncBit::Decode(callType) // exclude func 834514f5e3Sopenharmony_ci - HaveNewTargetBit::Decode(callType) // exclude new target 844514f5e3Sopenharmony_ci - HaveThisBit::Decode(callType)); // exclude this 854514f5e3Sopenharmony_ci SetSlotSize(slotSize); 864514f5e3Sopenharmony_ci} 874514f5e3Sopenharmony_ci 884514f5e3Sopenharmony_ci// It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods. 894514f5e3Sopenharmony_cistd::string MethodLiteral::ParseFunctionName(const JSPandaFile* jsPandaFile, EntityId methodId) 904514f5e3Sopenharmony_ci{ 914514f5e3Sopenharmony_ci std::string_view methodName = ParseFunctionNameView(jsPandaFile, methodId).first; 924514f5e3Sopenharmony_ci return std::string(methodName); 934514f5e3Sopenharmony_ci} 944514f5e3Sopenharmony_ci 954514f5e3Sopenharmony_ci// It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods. 964514f5e3Sopenharmony_cistd::pair<std::string_view, bool> MethodLiteral::ParseFunctionNameView( 974514f5e3Sopenharmony_ci const JSPandaFile* jsPandaFile, EntityId methodId) 984514f5e3Sopenharmony_ci{ 994514f5e3Sopenharmony_ci if (UNLIKELY(jsPandaFile == nullptr)) { 1004514f5e3Sopenharmony_ci return {"", true}; 1014514f5e3Sopenharmony_ci } 1024514f5e3Sopenharmony_ci 1034514f5e3Sopenharmony_ci auto [methodName, isASCII] = GetMethodNameView(jsPandaFile, methodId); 1044514f5e3Sopenharmony_ci if (LIKELY(methodName[0] != '#')) { 1054514f5e3Sopenharmony_ci return {methodName, isASCII}; 1064514f5e3Sopenharmony_ci } 1074514f5e3Sopenharmony_ci 1084514f5e3Sopenharmony_ci size_t index = methodName.find_last_of('#'); 1094514f5e3Sopenharmony_ci methodName = methodName.substr(index + 1); // #...#functionName 1104514f5e3Sopenharmony_ci if (index = methodName.find_last_of('^'); index != std::string::npos) { 1114514f5e3Sopenharmony_ci methodName = methodName.substr(0, index); // #...#functionName^1 1124514f5e3Sopenharmony_ci } 1134514f5e3Sopenharmony_ci return {methodName, isASCII}; 1144514f5e3Sopenharmony_ci} 1154514f5e3Sopenharmony_ci 1164514f5e3Sopenharmony_ci// It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods. 1174514f5e3Sopenharmony_ciCString MethodLiteral::ParseFunctionNameToCString(const JSPandaFile *jsPandaFile, EntityId methodId) 1184514f5e3Sopenharmony_ci{ 1194514f5e3Sopenharmony_ci if (jsPandaFile == nullptr) { 1204514f5e3Sopenharmony_ci return ""; 1214514f5e3Sopenharmony_ci } 1224514f5e3Sopenharmony_ci 1234514f5e3Sopenharmony_ci CString methodName(GetMethodName(jsPandaFile, methodId)); 1244514f5e3Sopenharmony_ci if (LIKELY(methodName[0] != '#')) { 1254514f5e3Sopenharmony_ci return methodName; 1264514f5e3Sopenharmony_ci } 1274514f5e3Sopenharmony_ci 1284514f5e3Sopenharmony_ci size_t index = methodName.find_last_of('#'); 1294514f5e3Sopenharmony_ci methodName = methodName.substr(index + 1); // #...#functionName 1304514f5e3Sopenharmony_ci if (methodName.find('^') != std::string::npos) { 1314514f5e3Sopenharmony_ci index = methodName.find_last_of('^'); 1324514f5e3Sopenharmony_ci methodName = methodName.substr(0, index); // #...#functionName^1 1334514f5e3Sopenharmony_ci } 1344514f5e3Sopenharmony_ci return methodName; 1354514f5e3Sopenharmony_ci} 1364514f5e3Sopenharmony_ci 1374514f5e3Sopenharmony_ciconst char* MethodLiteral::GetMethodName(const JSPandaFile* jsPandaFile, EntityId methodId, bool cpuProfiler) 1384514f5e3Sopenharmony_ci{ 1394514f5e3Sopenharmony_ci if (jsPandaFile == nullptr) { 1404514f5e3Sopenharmony_ci return ""; 1414514f5e3Sopenharmony_ci } 1424514f5e3Sopenharmony_ci return GetMethodNameView(jsPandaFile, methodId, cpuProfiler).first.data(); 1434514f5e3Sopenharmony_ci} 1444514f5e3Sopenharmony_ci 1454514f5e3Sopenharmony_cistd::pair<std::string_view, bool> MethodLiteral::GetMethodNameView( 1464514f5e3Sopenharmony_ci const JSPandaFile* jsPandaFile, EntityId methodId, bool cpuProfiler) 1474514f5e3Sopenharmony_ci{ 1484514f5e3Sopenharmony_ci ASSERT(jsPandaFile != nullptr && "jsPandaFile is null"); 1494514f5e3Sopenharmony_ci if (cpuProfiler) { 1504514f5e3Sopenharmony_ci return jsPandaFile->GetCpuProfilerMethodName(methodId); 1514514f5e3Sopenharmony_ci } 1524514f5e3Sopenharmony_ci return const_cast<JSPandaFile*>(jsPandaFile)->GetMethodName(methodId); 1534514f5e3Sopenharmony_ci} 1544514f5e3Sopenharmony_ci 1554514f5e3Sopenharmony_ciCString MethodLiteral::GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId) 1564514f5e3Sopenharmony_ci{ 1574514f5e3Sopenharmony_ci if (jsPandaFile == nullptr) { 1584514f5e3Sopenharmony_ci return ""; 1594514f5e3Sopenharmony_ci } 1604514f5e3Sopenharmony_ci 1614514f5e3Sopenharmony_ci return const_cast<JSPandaFile *>(jsPandaFile)->GetRecordName(methodId); 1624514f5e3Sopenharmony_ci} 1634514f5e3Sopenharmony_ci 1644514f5e3Sopenharmony_ciconst char *MethodLiteral::GetRecordNameWithSymbol(const JSPandaFile *jsPandaFile, EntityId methodId) 1654514f5e3Sopenharmony_ci{ 1664514f5e3Sopenharmony_ci if (jsPandaFile == nullptr) { 1674514f5e3Sopenharmony_ci return ""; 1684514f5e3Sopenharmony_ci } 1694514f5e3Sopenharmony_ci 1704514f5e3Sopenharmony_ci const panda_file::File *pf = jsPandaFile->GetPandaFile(); 1714514f5e3Sopenharmony_ci panda_file::MethodDataAccessor mda(*pf, methodId); 1724514f5e3Sopenharmony_ci panda_file::ClassDataAccessor cda(*pf, mda.GetClassId()); 1734514f5e3Sopenharmony_ci return utf::Mutf8AsCString(cda.GetDescriptor()); 1744514f5e3Sopenharmony_ci} 1754514f5e3Sopenharmony_ci 1764514f5e3Sopenharmony_ciuint32_t MethodLiteral::GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId) 1774514f5e3Sopenharmony_ci{ 1784514f5e3Sopenharmony_ci if (jsPandaFile == nullptr) { 1794514f5e3Sopenharmony_ci return 0; 1804514f5e3Sopenharmony_ci } 1814514f5e3Sopenharmony_ci 1824514f5e3Sopenharmony_ci const panda_file::File *pandaFile = jsPandaFile->GetPandaFile(); 1834514f5e3Sopenharmony_ci panda_file::MethodDataAccessor mda(*pandaFile, methodId); 1844514f5e3Sopenharmony_ci auto codeId = mda.GetCodeId().value(); 1854514f5e3Sopenharmony_ci if (!codeId.IsValid()) { 1864514f5e3Sopenharmony_ci return 0; 1874514f5e3Sopenharmony_ci } 1884514f5e3Sopenharmony_ci 1894514f5e3Sopenharmony_ci panda_file::CodeDataAccessor cda(*pandaFile, codeId); 1904514f5e3Sopenharmony_ci return cda.GetCodeSize(); 1914514f5e3Sopenharmony_ci} 1924514f5e3Sopenharmony_ci 1934514f5e3Sopenharmony_cistd::optional<std::set<uint32_t>> MethodLiteral::GetConcurrentRequestedModules(const JSPandaFile *jsPandaFile) const 1944514f5e3Sopenharmony_ci{ 1954514f5e3Sopenharmony_ci ASSERT(jsPandaFile != nullptr); 1964514f5e3Sopenharmony_ci const panda_file::File *pf = jsPandaFile->GetPandaFile(); 1974514f5e3Sopenharmony_ci EntityId methodId = GetMethodId(); 1984514f5e3Sopenharmony_ci panda_file::MethodDataAccessor mda(*pf, methodId); 1994514f5e3Sopenharmony_ci std::set<uint32_t> requestedModules; 2004514f5e3Sopenharmony_ci bool hasRequestedModules = false; 2014514f5e3Sopenharmony_ci mda.EnumerateAnnotations([&](EntityId annotationId) { 2024514f5e3Sopenharmony_ci panda_file::AnnotationDataAccessor ada(*pf, annotationId); 2034514f5e3Sopenharmony_ci auto *annotationName = reinterpret_cast<const char *>(pf->GetStringData(ada.GetClassId()).data); 2044514f5e3Sopenharmony_ci if (::strcmp("L_ESConcurrentModuleRequestsAnnotation;", annotationName) == 0) { 2054514f5e3Sopenharmony_ci hasRequestedModules = true; 2064514f5e3Sopenharmony_ci uint32_t elemCount = ada.GetCount(); 2074514f5e3Sopenharmony_ci for (uint32_t i = 0; i < elemCount; i++) { 2084514f5e3Sopenharmony_ci panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i); 2094514f5e3Sopenharmony_ci auto *elemName = reinterpret_cast<const char *>(pf->GetStringData(adae.GetNameId()).data); 2104514f5e3Sopenharmony_ci if (::strcmp("ConcurrentModuleRequest", elemName) == 0) { 2114514f5e3Sopenharmony_ci uint32_t index = adae.GetScalarValue().GetValue(); 2124514f5e3Sopenharmony_ci requestedModules.insert(index); 2134514f5e3Sopenharmony_ci } 2144514f5e3Sopenharmony_ci } 2154514f5e3Sopenharmony_ci } 2164514f5e3Sopenharmony_ci }); 2174514f5e3Sopenharmony_ci if (!hasRequestedModules) { 2184514f5e3Sopenharmony_ci return std::nullopt; 2194514f5e3Sopenharmony_ci } 2204514f5e3Sopenharmony_ci return requestedModules; 2214514f5e3Sopenharmony_ci} 2224514f5e3Sopenharmony_ci} // namespace panda::ecmascript 223