• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "ecmascript/jspandafile/method_literal.h"
17 
18 #include "ecmascript/interpreter/interpreter-inl.h"
19 #include "ecmascript/jspandafile/js_pandafile.h"
20 
21 #include "libpandafile/class_data_accessor.h"
22 #include "libpandafile/code_data_accessor-inl.h"
23 #include "libpandafile/method_data_accessor-inl.h"
24 
25 namespace panda::ecmascript {
MethodLiteral(EntityId methodId)26 MethodLiteral::MethodLiteral(EntityId methodId)
27 {
28     ASSERT(methodId.IsValid());
29     SetMethodId(methodId);
30 }
31 
Initialize(const JSPandaFile * jsPandaFile)32 void MethodLiteral::Initialize(const JSPandaFile *jsPandaFile)
33 {
34     const panda_file::File *pf = jsPandaFile->GetPandaFile();
35     EntityId methodId = GetMethodId();
36     panda_file::MethodDataAccessor mda(*pf, methodId);
37     auto codeId = mda.GetCodeId().value();
38     ASSERT(codeId.IsValid());
39 
40     panda_file::CodeDataAccessor cda(*pf, codeId);
41     nativePointerOrBytecodeArray_ = cda.GetInstructions();
42     uint32_t codeSize = cda.GetCodeSize();
43     SetHotnessCounter(EcmaInterpreter::GetHotnessCounter(codeSize));
44 
45     uint32_t callType = UINT32_MAX;  // UINT32_MAX means not found
46     uint32_t slotSize = 0;
47     mda.EnumerateAnnotations([&](EntityId annotationId) {
48         panda_file::AnnotationDataAccessor ada(*pf, annotationId);
49         auto *annotationName = reinterpret_cast<const char *>(pf->GetStringData(ada.GetClassId()).data);
50         if (::strcmp("L_ESCallTypeAnnotation;", annotationName) == 0) {
51             uint32_t elemCount = ada.GetCount();
52             for (uint32_t i = 0; i < elemCount; i++) {
53                 panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
54                 auto *elemName = reinterpret_cast<const char *>(pf->GetStringData(adae.GetNameId()).data);
55                 if (::strcmp("callType", elemName) == 0) {
56                     callType = adae.GetScalarValue().GetValue();
57                 }
58             }
59         } else if (::strcmp("L_ESSlotNumberAnnotation;", annotationName) == 0) {
60             uint32_t elemCount = ada.GetCount();
61             for (uint32_t i = 0; i < elemCount; i++) {
62                 panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
63                 auto *elemName = reinterpret_cast<const char *>(pf->GetStringData(adae.GetNameId()).data);
64                 if (::strcmp("SlotNumber", elemName) == 0) {
65                     slotSize = adae.GetScalarValue().GetValue();
66                 }
67             }
68         }
69     });
70 
71     uint32_t numVregs = cda.GetNumVregs();
72     uint32_t numArgs = cda.GetNumArgs();
73     // Needed info for call can be got by loading callField only once.
74     // Native bit will be set in NewMethodForNativeFunction();
75     callField_ = (callType & CALL_TYPE_MASK) |
76                  NumVregsBits::Encode(numVregs) |
77                  NumArgsBits::Encode(numArgs - HaveFuncBit::Decode(callType)  // exclude func
78                                              - HaveNewTargetBit::Decode(callType)  // exclude new target
79                                              - HaveThisBit::Decode(callType));  // exclude this
80     SetSlotSize(slotSize);
81 }
82 
83 // It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods.
ParseFunctionName(const JSPandaFile * jsPandaFile,EntityId methodId)84 std::string MethodLiteral::ParseFunctionName(const JSPandaFile *jsPandaFile, EntityId methodId)
85 {
86     if (jsPandaFile == nullptr) {
87         return std::string();
88     }
89 
90     std::string methodName(GetMethodName(jsPandaFile, methodId));
91     if (LIKELY(methodName[0] != '#')) {
92         return methodName;
93     }
94 
95     size_t index = methodName.find_last_of('#');
96     return methodName.substr(index + 1);
97 }
98 
99 // It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods.
ParseFunctionNameToCString(const JSPandaFile * jsPandaFile,EntityId methodId)100 CString MethodLiteral::ParseFunctionNameToCString(const JSPandaFile *jsPandaFile, EntityId methodId)
101 {
102     if (jsPandaFile == nullptr) {
103         return "";
104     }
105 
106     CString methodName(GetMethodName(jsPandaFile, methodId));
107     if (LIKELY(methodName[0] != '#')) {
108         return methodName;
109     }
110 
111     size_t index = methodName.find_last_of('#');
112     return methodName.substr(index + 1);
113 }
114 
GetMethodName(const JSPandaFile * jsPandaFile,EntityId methodId,bool cpuProfiler)115 const char *MethodLiteral::GetMethodName(const JSPandaFile *jsPandaFile, EntityId methodId, bool cpuProfiler)
116 {
117     if (jsPandaFile == nullptr) {
118         return "";
119     }
120     if (cpuProfiler) {
121         return const_cast<JSPandaFile *>(jsPandaFile)->GetCpuProfilerMethodName(methodId);
122     }
123     return const_cast<JSPandaFile *>(jsPandaFile)->GetMethodName(methodId);
124 }
125 
GetRecordName(const JSPandaFile * jsPandaFile,EntityId methodId)126 CString MethodLiteral::GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId)
127 {
128     if (jsPandaFile == nullptr) {
129         return "";
130     }
131 
132     return const_cast<JSPandaFile *>(jsPandaFile)->GetRecordName(methodId);
133 }
134 
GetRecordNameWithSymbol(const JSPandaFile * jsPandaFile,EntityId methodId)135 const char *MethodLiteral::GetRecordNameWithSymbol(const JSPandaFile *jsPandaFile, EntityId methodId)
136 {
137     if (jsPandaFile == nullptr) {
138         return "";
139     }
140 
141     const panda_file::File *pf = jsPandaFile->GetPandaFile();
142     panda_file::MethodDataAccessor mda(*pf, methodId);
143     panda_file::ClassDataAccessor cda(*pf, mda.GetClassId());
144     return utf::Mutf8AsCString(cda.GetDescriptor());
145 }
146 
GetCodeSize(const JSPandaFile * jsPandaFile,EntityId methodId)147 uint32_t MethodLiteral::GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId)
148 {
149     if (jsPandaFile == nullptr) {
150         return 0;
151     }
152 
153     const panda_file::File *pandaFile = jsPandaFile->GetPandaFile();
154     panda_file::MethodDataAccessor mda(*pandaFile, methodId);
155     auto codeId = mda.GetCodeId().value();
156     if (!codeId.IsValid()) {
157         return 0;
158     }
159 
160     panda_file::CodeDataAccessor cda(*pandaFile, codeId);
161     return cda.GetCodeSize();
162 }
163 
GetConcurrentRequestedModules(const JSPandaFile * jsPandaFile) const164 std::optional<std::set<uint32_t>> MethodLiteral::GetConcurrentRequestedModules(const JSPandaFile *jsPandaFile) const
165 {
166     const panda_file::File *pf = jsPandaFile->GetPandaFile();
167     EntityId methodId = GetMethodId();
168     panda_file::MethodDataAccessor mda(*pf, methodId);
169     std::set<uint32_t> requestedModules;
170     bool hasRequestedModules = false;
171     mda.EnumerateAnnotations([&](EntityId annotationId) {
172         panda_file::AnnotationDataAccessor ada(*pf, annotationId);
173         auto *annotationName = reinterpret_cast<const char *>(pf->GetStringData(ada.GetClassId()).data);
174         if (::strcmp("L_ESConcurrentModuleRequestsAnnotation;", annotationName) == 0) {
175             hasRequestedModules = true;
176             uint32_t elemCount = ada.GetCount();
177             for (uint32_t i = 0; i < elemCount; i++) {
178                 panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
179                 auto *elemName = reinterpret_cast<const char *>(pf->GetStringData(adae.GetNameId()).data);
180                 if (::strcmp("ConcurrentModuleRequest", elemName) == 0) {
181                     uint32_t index = adae.GetScalarValue().GetValue();
182                     requestedModules.insert(index);
183                 }
184             }
185         }
186     });
187     if (!hasRequestedModules) {
188         return std::nullopt;
189     }
190     return requestedModules;
191 }
192 } // namespace panda::ecmascript
193