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/jspandafile/js_pandafile.h"
19
20 #include "libpandafile/class_data_accessor.h"
21 #include "libpandafile/code_data_accessor-inl.h"
22 #include "libpandafile/method_data_accessor-inl.h"
23
24 namespace panda::ecmascript {
MethodLiteral(const JSPandaFile * jsPandaFile,EntityId methodId)25 MethodLiteral::MethodLiteral(const JSPandaFile *jsPandaFile, EntityId methodId)
26 {
27 if (jsPandaFile != nullptr) {
28 panda_file::MethodDataAccessor mda(*(jsPandaFile->GetPandaFile()), methodId);
29 auto codeId = mda.GetCodeId().value();
30 if (!codeId.IsValid()) {
31 nativePointerOrBytecodeArray_ = nullptr;
32 }
33 panda_file::CodeDataAccessor cda(*(jsPandaFile->GetPandaFile()), codeId);
34 nativePointerOrBytecodeArray_ = cda.GetInstructions();
35 }
36 SetHotnessCounter(static_cast<int16_t>(0));
37 SetMethodId(methodId);
38 }
39
Initialize(const JSPandaFile * jsPandaFile,uint32_t numVregs,uint32_t numArgs)40 void MethodLiteral::Initialize(const JSPandaFile *jsPandaFile, uint32_t numVregs, uint32_t numArgs)
41 {
42 uint32_t callType = UINT32_MAX; // UINT32_MAX means not found
43 uint32_t slotSize = 0;
44 const panda_file::File *pandaFile = jsPandaFile->GetPandaFile();
45 panda_file::MethodDataAccessor mda(*pandaFile, GetMethodId());
46 mda.EnumerateAnnotations([&](EntityId annotation_id) {
47 panda_file::AnnotationDataAccessor ada(*pandaFile, annotation_id);
48 auto *annotationName = reinterpret_cast<const char *>(pandaFile->GetStringData(ada.GetClassId()).data);
49 if (::strcmp("L_ESCallTypeAnnotation;", annotationName) == 0) {
50 uint32_t elemCount = ada.GetCount();
51 for (uint32_t i = 0; i < elemCount; i++) {
52 panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
53 auto *elemName = reinterpret_cast<const char *>(pandaFile->GetStringData(adae.GetNameId()).data);
54 if (::strcmp("callType", elemName) == 0) {
55 callType = adae.GetScalarValue().GetValue();
56 }
57 }
58 } else if (::strcmp("L_ESSlotNumberAnnotation;", annotationName) == 0) {
59 uint32_t elemCount = ada.GetCount();
60 for (uint32_t i = 0; i < elemCount; i++) {
61 panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
62 auto *elemName = reinterpret_cast<const char *>(pandaFile->GetStringData(adae.GetNameId()).data);
63 if (::strcmp("SlotNumber", elemName) == 0) {
64 slotSize = adae.GetScalarValue().GetValue();
65 }
66 }
67 }
68 });
69 // Needed info for call can be got by loading callField only once.
70 // Native bit will be set in NewMethodForNativeFunction();
71 callField_ = (callType & CALL_TYPE_MASK) |
72 NumVregsBits::Encode(numVregs) |
73 NumArgsBits::Encode(numArgs - HaveFuncBit::Decode(callType) // exclude func
74 - HaveNewTargetBit::Decode(callType) // exclude new target
75 - HaveThisBit::Decode(callType)); // exclude this
76 SetSlotSize(slotSize);
77 }
78
79 // It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods.
ParseFunctionName(const JSPandaFile * jsPandaFile,EntityId methodId)80 std::string MethodLiteral::ParseFunctionName(const JSPandaFile *jsPandaFile, EntityId methodId)
81 {
82 if (jsPandaFile == nullptr) {
83 return std::string();
84 }
85 std::string methodName(utf::Mutf8AsCString(GetName(jsPandaFile, methodId).data));
86 if (LIKELY(methodName[0] != '#')) {
87 return methodName;
88 }
89 size_t index = methodName.find_last_of('#');
90 return methodName.substr(index + 1);
91 }
92
GetMethodName(const JSPandaFile * jsPandaFile,EntityId methodId)93 const char *MethodLiteral::GetMethodName(const JSPandaFile *jsPandaFile, EntityId methodId)
94 {
95 if (jsPandaFile == nullptr) {
96 return "";
97 }
98 return utf::Mutf8AsCString(GetName(jsPandaFile, methodId).data);
99 }
100
GetName(const JSPandaFile * jsPandaFile,EntityId methodId)101 panda_file::File::StringData MethodLiteral::GetName(const JSPandaFile *jsPandaFile, EntityId methodId)
102 {
103 panda_file::MethodDataAccessor mda(*(jsPandaFile->GetPandaFile()), methodId);
104 return jsPandaFile->GetPandaFile()->GetStringData(mda.GetNameId());
105 }
106
GetRecordName(const JSPandaFile * jsPandaFile,EntityId methodId)107 CString MethodLiteral::GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId)
108 {
109 if (jsPandaFile == nullptr) {
110 return "";
111 }
112
113 const panda_file::File *pf = jsPandaFile->GetPandaFile();
114 panda_file::MethodDataAccessor mda(*pf, methodId);
115 panda_file::ClassDataAccessor cda(*pf, mda.GetClassId());
116 CString desc = utf::Mutf8AsCString(cda.GetDescriptor());
117 return jsPandaFile->ParseEntryPoint(desc);
118 }
119
GetNumVregs(const JSPandaFile * jsPandaFile,const MethodLiteral * methodLiteral)120 uint32_t MethodLiteral::GetNumVregs(const JSPandaFile *jsPandaFile, const MethodLiteral *methodLiteral)
121 {
122 if (jsPandaFile == nullptr) {
123 return 0;
124 }
125 panda_file::MethodDataAccessor mda(*(jsPandaFile->GetPandaFile()), methodLiteral->GetMethodId());
126 auto codeId = mda.GetCodeId().value();
127 if (!codeId.IsValid()) {
128 return 0;
129 }
130 panda_file::CodeDataAccessor cda(*(jsPandaFile->GetPandaFile()), codeId);
131 return cda.GetNumVregs();
132 }
133
GetCodeSize(const JSPandaFile * jsPandaFile,EntityId methodId)134 uint32_t MethodLiteral::GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId)
135 {
136 if (jsPandaFile == nullptr) {
137 return 0;
138 }
139 const panda_file::File *pandaFile = jsPandaFile->GetPandaFile();
140 panda_file::MethodDataAccessor mda(*pandaFile, methodId);
141 auto codeId = mda.GetCodeId().value();
142 if (!codeId.IsValid()) {
143 return 0;
144 }
145 panda_file::CodeDataAccessor cda(*pandaFile, codeId);
146 return cda.GetCodeSize();
147 }
148 } // namespace panda::ecmascript
149