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
GetMethodName(const JSPandaFile * jsPandaFile,EntityId methodId)99 const char *MethodLiteral::GetMethodName(const JSPandaFile *jsPandaFile, EntityId methodId)
100 {
101 if (jsPandaFile == nullptr) {
102 return "";
103 }
104
105 const panda_file::File *pf = jsPandaFile->GetPandaFile();
106 panda_file::MethodDataAccessor mda(*pf, methodId);
107 auto sd = jsPandaFile->GetStringData(mda.GetNameId());
108 return utf::Mutf8AsCString(sd.data);
109 }
110
GetRecordName(const JSPandaFile * jsPandaFile,EntityId methodId)111 CString MethodLiteral::GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId)
112 {
113 if (jsPandaFile == nullptr) {
114 return "";
115 }
116
117 const panda_file::File *pf = jsPandaFile->GetPandaFile();
118 panda_file::MethodDataAccessor mda(*pf, methodId);
119 panda_file::ClassDataAccessor cda(*pf, mda.GetClassId());
120 CString desc = utf::Mutf8AsCString(cda.GetDescriptor());
121 return JSPandaFile::ParseEntryPoint(desc);
122 }
123
GetRecordNameWithSymbol(const JSPandaFile * jsPandaFile,EntityId methodId)124 const char *MethodLiteral::GetRecordNameWithSymbol(const JSPandaFile *jsPandaFile, EntityId methodId)
125 {
126 if (jsPandaFile == nullptr) {
127 return "";
128 }
129
130 const panda_file::File *pf = jsPandaFile->GetPandaFile();
131 panda_file::MethodDataAccessor mda(*pf, methodId);
132 panda_file::ClassDataAccessor cda(*pf, mda.GetClassId());
133 return utf::Mutf8AsCString(cda.GetDescriptor());
134 }
135
GetCodeSize(const JSPandaFile * jsPandaFile,EntityId methodId)136 uint32_t MethodLiteral::GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId)
137 {
138 if (jsPandaFile == nullptr) {
139 return 0;
140 }
141
142 const panda_file::File *pandaFile = jsPandaFile->GetPandaFile();
143 panda_file::MethodDataAccessor mda(*pandaFile, methodId);
144 auto codeId = mda.GetCodeId().value();
145 if (!codeId.IsValid()) {
146 return 0;
147 }
148
149 panda_file::CodeDataAccessor cda(*pandaFile, codeId);
150 return cda.GetCodeSize();
151 }
152 } // namespace panda::ecmascript
153