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