1 /*
2 * Copyright (c) 2021 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 #ifndef ECMASCRIPT_JS_METHOD_H
17 #define ECMASCRIPT_JS_METHOD_H
18
19 #include "ecmascript/mem/c_string.h"
20 #include "include/method.h"
21 #include "libpandafile/file.h"
22
23 static constexpr uint32_t CALL_TYPE_MASK = 0xF; // 0xF: the last 4 bits are used as callType
24 static constexpr size_t STORAGE_32_NUM = 4;
25 static constexpr size_t STORAGE_PTR_NUM = 3;
26
27 #define JS_METHOD_OFFSET_LIST(V) \
28 V(STORPTR, STOR32, STORAGE_32_NUM * sizeof(uint32_t), STORAGE_32_NUM * sizeof(uint32_t)) \
29 V(PANDAFILE, STORPTR, STORAGE_PTR_NUM * sizeof(uint32_t), STORAGE_PTR_NUM * sizeof(uint64_t)) \
30 V(FILEID, PANDAFILE, sizeof(uint32_t), sizeof(uint64_t)) \
31 V(CODEID, FILEID, sizeof(uint32_t), sizeof(uint32_t)) \
32 V(SHORTY, CODEID, sizeof(uint32_t), sizeof(uint32_t)) \
33 V(PROFILINGDATA, SHORTY, sizeof(uint32_t), sizeof(uint64_t)) \
34 V(BYTECODEARRAY, PROFILINGDATA, sizeof(uint32_t), sizeof(uint64_t)) \
35 V(BYTECODEARRAYSIZE, BYTECODEARRAY, sizeof(uint32_t), sizeof(uint64_t)) \
36 V(SLOTSIZE, BYTECODEARRAYSIZE, sizeof(uint32_t), sizeof(uint32_t)) \
37 V(CALLFIELD, SLOTSIZE, sizeof(uint8_t), sizeof(uint8_t)) \
38
39 static constexpr uint32_t JS_METHOD_STOR32_OFFSET_32 = 0U;
40 static constexpr uint32_t JS_METHOD_STOR32_OFFSET_64 = 0U;
41 #define JS_METHOD_OFFSET_MACRO(name, lastName, lastSize32, lastSize64) \
42 static constexpr uint32_t JS_METHOD_##name##_OFFSET_32 = JS_METHOD_##lastName##_OFFSET_32 + (lastSize32); \
43 static constexpr uint32_t JS_METHOD_##name##_OFFSET_64 = JS_METHOD_##lastName##_OFFSET_64 + (lastSize64);
JS_METHOD_OFFSET_LIST(JS_METHOD_OFFSET_MACRO)44 JS_METHOD_OFFSET_LIST(JS_METHOD_OFFSET_MACRO)
45 #undef JS_METHOD_OFFSET_MACRO
46
47 namespace panda::ecmascript {
48 class JSPandaFile;
49
50 class JSMethod : public Method {
51 public:
52 static constexpr uint8_t MAX_SLOT_SIZE = 0xFF;
53 static constexpr uint32_t HOTNESS_COUNTER_OFFSET = 3 * sizeof(uint32_t); // 3: the 3th field of method
54
55 static JSMethod *Cast(Method *method)
56 {
57 return static_cast<JSMethod *>(method);
58 }
59
60 JSMethod(const JSPandaFile *jsPandaFile, panda_file::File::EntityId fileId,
61 panda_file::File::EntityId codeId, uint32_t accessFlags, uint32_t numArgs, const uint16_t *shorty);
62 JSMethod() = delete;
63 ~JSMethod() = default;
64 JSMethod(const JSMethod &) = delete;
65 JSMethod(JSMethod &&) = delete;
66 JSMethod &operator=(const JSMethod &) = delete;
67 JSMethod &operator=(JSMethod &&) = delete;
68
69 static constexpr uint32_t GetBytecodeArrayOffset()
70 {
71 return MEMBER_OFFSET(JSMethod, bytecodeArray_);
72 }
73
74 static constexpr uint32_t GetBytecodeArrayOffset(bool isArm32)
75 {
76 if (isArm32) {
77 return JS_METHOD_BYTECODEARRAY_OFFSET_32;
78 }
79 return JS_METHOD_BYTECODEARRAY_OFFSET_64;
80 }
81
82 const uint8_t *GetBytecodeArray() const
83 {
84 return bytecodeArray_;
85 }
86
87 uint32_t GetBytecodeArraySize() const
88 {
89 return bytecodeArraySize_;
90 }
91
92 void SetBytecodeArray(const uint8_t *bc)
93 {
94 bytecodeArray_ = bc;
95 }
96
97 uint8_t GetSlotSize() const
98 {
99 return slotSize_;
100 }
101
102 void UpdateSlotSize (uint8_t size)
103 {
104 uint16_t end = GetSlotSize() + size;
105 if (end >= MAX_SLOT_SIZE) {
106 slotSize_ = MAX_SLOT_SIZE;
107 return;
108 }
109 slotSize_ = static_cast<uint8_t>(end);
110 }
111
112 static constexpr size_t VREGS_ARGS_NUM_BITS = 28; // 28: maximum 268,435,455
113 using HaveThisBit = BitField<bool, 0, 1>; // offset 0
114 using HaveNewTargetBit = HaveThisBit::NextFlag; // offset 1
115 using HaveExtraBit = HaveNewTargetBit::NextFlag; // offset 2
116 using HaveFuncBit = HaveExtraBit::NextFlag; // offset 3
117 using NumVregsBits = HaveFuncBit::NextField<uint32_t, VREGS_ARGS_NUM_BITS>; // offset 4-31
118 using NumArgsBits = NumVregsBits::NextField<uint32_t, VREGS_ARGS_NUM_BITS>; // offset 32-59
119 using IsNativeBit = NumArgsBits::NextFlag; // offset 60
120
121 uint64_t GetCallField() const
122 {
123 return callField_;
124 }
125
126 void SetNativeBit(bool isNative)
127 {
128 callField_ = IsNativeBit::Update(callField_, isNative);
129 }
130
131 std::string ParseFunctionName() const;
132 void InitializeCallField();
133
134 bool HaveThisWithCallField() const
135 {
136 return HaveThisBit::Decode(callField_);
137 }
138
139 bool HaveNewTargetWithCallField() const
140 {
141 return HaveNewTargetBit::Decode(callField_);
142 }
143
144 bool HaveExtraWithCallField() const
145 {
146 return HaveExtraBit::Decode(callField_);
147 }
148
149 bool HaveFuncWithCallField() const
150 {
151 return HaveFuncBit::Decode(callField_);
152 }
153
154 bool IsNativeWithCallField() const
155 {
156 return IsNativeBit::Decode(callField_);
157 }
158
159 bool OnlyHaveThisWithCallField() const
160 {
161 return (callField_ & CALL_TYPE_MASK) == 1; // 1: the first bit of callFiled is HaveThisBit
162 }
163
164 uint32_t GetNumVregsWithCallField() const
165 {
166 return NumVregsBits::Decode(callField_);
167 }
168
169 uint32_t GetNumArgsWithCallField() const
170 {
171 return NumArgsBits::Decode(callField_);
172 }
173 panda_file::File::EntityId GetMethodId() const
174 {
175 return GetFileId();
176 }
177 const JSPandaFile *GetJSPandaFile() const
178 {
179 return jsPandaFile_;
180 }
181
182 private:
183 const uint8_t *bytecodeArray_ {nullptr};
184 uint32_t bytecodeArraySize_ {0};
185 uint8_t slotSize_ {0};
186 uint64_t callField_ {0};
187 const JSPandaFile *jsPandaFile_ {nullptr};
188 };
189 } // namespace panda::ecmascript
190
191 #endif // ECMASCRIPT_JS_METHOD_H
192