1 /*
2 * Copyright (c) 2023 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/compiler/profiler_stub_builder.h"
17
18 #include "ecmascript/compiler/interpreter_stub-inl.h"
19 #include "ecmascript/compiler/stub_builder-inl.h"
20 #include "ecmascript/ic/profile_type_info.h"
21
22 namespace panda::ecmascript::kungfu {
PGOProfiler(GateRef glue,GateRef pc,GateRef func,GateRef profileTypeInfo,const std::vector<GateRef> & values,OperationType type)23 void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo,
24 const std::vector<GateRef> &values, OperationType type)
25 {
26 switch (type) {
27 case OperationType::CALL:
28 ProfileCall(glue, pc, func, values[0]);
29 break;
30 case OperationType::OPERATION_TYPE:
31 ProfileOpType(glue, pc, func, profileTypeInfo, values[0]);
32 break;
33 case OperationType::DEFINE_CLASS:
34 ProfileDefineClass(glue, pc, func, values[0]);
35 break;
36 case OperationType::CREATE_OBJECT:
37 ProfileCreateObject(glue, pc, func, values[0]);
38 break;
39 case OperationType::STORE_LAYOUT:
40 ProfileObjLayout(glue, pc, func, values[0], Int32(1));
41 break;
42 case OperationType::LOAD_LAYOUT:
43 ProfileObjLayout(glue, pc, func, values[0], Int32(0));
44 break;
45 default:
46 break;
47 }
48 }
49
ProfileOpType(GateRef glue,GateRef pc,GateRef func,GateRef profileTypeInfo,GateRef type)50 void ProfilerStubBuilder::ProfileOpType(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo, GateRef type)
51 {
52 auto env = GetEnvironment();
53 Label subEntry(env);
54 env->SubCfgEntry(&subEntry);
55
56 Label exit(env);
57 Label profiler(env);
58 Label slowpath(env);
59 Branch(TaggedIsUndefined(profileTypeInfo), &slowpath, &profiler);
60 Bind(&slowpath);
61 {
62 GateRef method = Load(VariableType::JS_ANY(), func, IntPtr(JSFunctionBase::METHOD_OFFSET));
63 GateRef firstPC = Load(VariableType::NATIVE_POINTER(), method,
64 IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
65 GateRef offset = TruncPtrToInt32(PtrSub(pc, firstPC));
66 CallNGCRuntime(glue, RTSTUB_ID(ProfileOpType), { glue, func, offset, type });
67 Jump(&exit);
68 }
69 Bind(&profiler);
70 {
71 Label uninitialize(env);
72 Label compareLabel(env);
73 Label updateSlot(env);
74 Label updateProfile(env);
75
76 GateRef slotId = ZExtInt8ToInt32(Load(VariableType::INT8(), pc, IntPtr(1)));
77 GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId);
78 DEFVARIABLE(curType, VariableType::INT32(), type);
79 Branch(TaggedIsInt(slotValue), &compareLabel, &uninitialize);
80 Bind(&compareLabel);
81 {
82 GateRef oldSlotValue = TaggedGetInt(slotValue);
83 curType = Int32Or(oldSlotValue, type);
84 Branch(Int32Equal(oldSlotValue, *curType), &exit, &updateSlot);
85 }
86 Bind(&uninitialize);
87 {
88 Branch(TaggedIsUndefined(slotValue), &updateSlot, &updateProfile);
89 }
90 Bind(&updateSlot);
91 {
92 SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, IntToTaggedInt(*curType));
93 Jump(&updateProfile);
94 }
95 Bind(&updateProfile);
96 {
97 GateRef method = Load(VariableType::JS_ANY(), func, IntPtr(JSFunctionBase::METHOD_OFFSET));
98 GateRef firstPC =
99 Load(VariableType::NATIVE_POINTER(), method, IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
100 GateRef offset = TruncPtrToInt32(PtrSub(pc, firstPC));
101 CallNGCRuntime(glue, RTSTUB_ID(ProfileOpType), { glue, func, offset, *curType });
102 Jump(&exit);
103 }
104 }
105 Bind(&exit);
106 env->SubCfgExit();
107 }
108
ProfileDefineClass(GateRef glue,GateRef pc,GateRef func,GateRef constructor)109 void ProfilerStubBuilder::ProfileDefineClass(GateRef glue, GateRef pc, GateRef func, GateRef constructor)
110 {
111 auto env = GetEnvironment();
112 Label subEntry(env);
113 env->SubCfgEntry(&subEntry);
114
115 GateRef method = Load(VariableType::JS_ANY(), func, IntPtr(JSFunctionBase::METHOD_OFFSET));
116 GateRef firstPC =
117 Load(VariableType::NATIVE_POINTER(), method, IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
118 GateRef offset = TruncPtrToInt32(PtrSub(pc, firstPC));
119 CallNGCRuntime(glue, RTSTUB_ID(ProfileDefineClass), { glue, func, offset, constructor });
120
121 env->SubCfgExit();
122 }
123
ProfileCreateObject(GateRef glue,GateRef pc,GateRef func,GateRef newObj)124 void ProfilerStubBuilder::ProfileCreateObject(GateRef glue, GateRef pc, GateRef func, GateRef newObj)
125 {
126 auto env = GetEnvironment();
127 Label subEntry(env);
128 env->SubCfgEntry(&subEntry);
129 Label exit(env);
130
131 DEFVARIABLE(traceId, VariableType::INT32(), Int32(0));
132 Label isArray(env);
133 Label profile(env);
134 Label calculateTraceId(env);
135 Branch(TaggedIsJSArray(newObj), &isArray, &calculateTraceId);
136 Bind(&isArray);
137 {
138 GateRef traceIdOffset = IntPtr(JSArray::TRACE_INDEX_OFFSET);
139 traceId = Load(VariableType::INT32(), newObj, traceIdOffset);
140 Label uninitialize(env);
141 Branch(Int32GreaterThan(*traceId, Int32(0)), &exit, &uninitialize);
142 Bind(&uninitialize);
143 {
144 auto pfAddr = LoadPfHeaderFromConstPool(func);
145 traceId = TruncPtrToInt32(PtrSub(pc, pfAddr));
146 Store(VariableType::INT32(), glue, newObj, traceIdOffset, *traceId);
147 Jump(&profile);
148 }
149 }
150 Bind(&calculateTraceId);
151 {
152 auto pfAddr = LoadPfHeaderFromConstPool(func);
153 traceId = TruncPtrToInt32(PtrSub(pc, pfAddr));
154 Jump(&profile);
155 }
156 Bind(&profile);
157 {
158 GateRef method = Load(VariableType::JS_ANY(), func, IntPtr(JSFunctionBase::METHOD_OFFSET));
159 GateRef firstPC =
160 Load(VariableType::NATIVE_POINTER(), method, IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
161 GateRef offset = TruncPtrToInt32(PtrSub(pc, firstPC));
162 CallNGCRuntime(glue, RTSTUB_ID(ProfileCreateObject), { glue, func, offset, newObj, *traceId });
163 Jump(&exit);
164 }
165 Bind(&exit);
166 env->SubCfgExit();
167 }
168
ProfileObjLayout(GateRef glue,GateRef pc,GateRef func,GateRef object,GateRef store)169 void ProfilerStubBuilder::ProfileObjLayout(GateRef glue, GateRef pc, GateRef func, GateRef object, GateRef store)
170 {
171 auto env = GetEnvironment();
172 Label subEntry(env);
173 env->SubCfgEntry(&subEntry);
174 Label isHeap(env);
175 Label exit(env);
176 Branch(TaggedIsHeapObject(object), &isHeap, &exit);
177 Bind(&isHeap);
178 {
179 GateRef method = Load(VariableType::JS_ANY(), func, IntPtr(JSFunctionBase::METHOD_OFFSET));
180 GateRef firstPC =
181 Load(VariableType::NATIVE_POINTER(), method, IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
182 GateRef offset = TruncPtrToInt32(PtrSub(pc, firstPC));
183 CallNGCRuntime(glue, RTSTUB_ID(ProfileObjLayout), { glue, func, offset, object, store });
184 Jump(&exit);
185 }
186 Bind(&exit);
187 env->SubCfgExit();
188 }
189
ProfileCall(GateRef glue,GateRef pc,GateRef func,GateRef target)190 void ProfilerStubBuilder::ProfileCall(GateRef glue, GateRef pc, GateRef func, GateRef target)
191 {
192 auto env = GetEnvironment();
193 Label subEntry(env);
194 env->SubCfgEntry(&subEntry);
195
196 Label exit(env);
197 Label slowpath(env);
198 Label fastpath(env);
199
200 Label targetIsFunction(env);
201 Branch(IsJSFunction(target), &targetIsFunction, &exit);
202 Bind(&targetIsFunction);
203 {
204 GateRef targetProfileInfo = GetProfileTypeInfo(target);
205 Label nonHotness(env);
206 Branch(TaggedIsUndefined(targetProfileInfo), &nonHotness, &exit);
207 Bind(&nonHotness);
208 {
209 GateRef method = Load(VariableType::JS_ANY(), func, IntPtr(JSFunctionBase::METHOD_OFFSET));
210 GateRef firstPC =
211 Load(VariableType::NATIVE_POINTER(), method, IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
212 GateRef offset = TruncPtrToInt32(PtrSub(pc, firstPC));
213 CallNGCRuntime(glue, RTSTUB_ID(ProfileCall), { glue, func, target, offset, Int32(1)});
214 Jump(&exit);
215 }
216 }
217 Bind(&exit);
218 env->SubCfgExit();
219 }
220
UpdateTrackTypeInPropAttr(GateRef attr,GateRef value,ProfileOperation callback)221 GateRef ProfilerStubBuilder::UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback)
222 {
223 if (callback.IsEmpty()) {
224 return attr;
225 }
226 auto env = GetEnvironment();
227 Label entry(env);
228 env->SubCfgEntry(&entry);
229
230 GateRef oldTrackType = GetTrackTypeInPropAttr(attr);
231 DEFVARIABLE(newTrackType, VariableType::INT32(), Int32(static_cast<int32_t>(TrackType::TAGGED)));
232 DEFVARIABLE(result, VariableType::INT32(), attr);
233
234 Label exit(env);
235 Label judgeValue(env);
236 Branch(Equal(oldTrackType, Int32(static_cast<int32_t>(TrackType::TAGGED))), &exit, &judgeValue);
237 Bind(&judgeValue);
238 {
239 newTrackType = TaggedToTrackType(value);
240 Label update(env);
241 Label merge(env);
242 Branch(Int32Equal(*newTrackType, Int32(static_cast<int32_t>(TrackType::TAGGED))), &update, &merge);
243 Bind(&merge);
244 {
245 newTrackType = Int32Or(oldTrackType, *newTrackType);
246 Branch(Int32Equal(oldTrackType, *newTrackType), &exit, &update);
247 }
248 Bind(&update);
249 {
250 result = SetTrackTypeInPropAttr(attr, *newTrackType);
251 Jump(&exit);
252 }
253 }
254 Bind(&exit);
255 auto ret = *result;
256 env->SubCfgExit();
257 return ret;
258 }
259
UpdatePropAttrIC(GateRef glue,GateRef receiver,GateRef value,GateRef handler,ProfileOperation callback)260 void ProfilerStubBuilder::UpdatePropAttrIC(
261 GateRef glue, GateRef receiver, GateRef value, GateRef handler, ProfileOperation callback)
262 {
263 if (callback.IsEmpty()) {
264 return;
265 }
266 GateRef attrIndex = HandlerBaseGetAttrIndex(handler);
267 GateRef hclass = LoadHClass(receiver);
268 GateRef layout = GetLayoutFromHClass(hclass);
269 GateRef propAttr = GetPropAttrFromLayoutInfo(layout, attrIndex);
270 GateRef attr = GetInt32OfTInt(propAttr);
271 UpdatePropAttrWithValue(glue, receiver, layout, attr, attrIndex, value, callback);
272 }
273
UpdatePropAttrWithValue(GateRef glue,GateRef receiver,GateRef layout,GateRef attr,GateRef attrIndex,GateRef value,ProfileOperation callback)274 void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef receiver, GateRef layout, GateRef attr,
275 GateRef attrIndex, GateRef value, ProfileOperation callback)
276 {
277 if (callback.IsEmpty()) {
278 return;
279 }
280 auto env = GetEnvironment();
281 Label entry(env);
282 env->SubCfgEntry(&entry);
283 Label exit(env);
284 Label updateLayout(env);
285 GateRef newAttr = UpdateTrackTypeInPropAttr(attr, value, callback);
286 Branch(Equal(attr, newAttr), &exit, &updateLayout);
287 Bind(&updateLayout);
288 {
289 SetPropAttrToLayoutInfo(glue, layout, attrIndex, newAttr);
290 callback.ProfileObjLayoutByStore(receiver);
291 Jump(&exit);
292 }
293 Bind(&exit);
294 env->SubCfgExit();
295 }
296
TaggedToTrackType(GateRef value)297 GateRef ProfilerStubBuilder::TaggedToTrackType(GateRef value)
298 {
299 auto env = GetEnvironment();
300 Label entry(env);
301 env->SubCfgEntry(&entry);
302
303 DEFVARIABLE(newTrackType, VariableType::INT32(), Int32(static_cast<int32_t>(TrackType::TAGGED)));
304 Label exit(env);
305 Label isInt(env);
306 Label notInt(env);
307 Branch(TaggedIsInt(value), &isInt, ¬Int);
308 Bind(&isInt);
309 {
310 newTrackType = Int32(static_cast<int32_t>(TrackType::INT));
311 Jump(&exit);
312 }
313 Bind(¬Int);
314 {
315 Label isObject(env);
316 Label isDouble(env);
317 Branch(TaggedIsObject(value), &isObject, &isDouble);
318 Bind(&isObject);
319 {
320 newTrackType = Int32(static_cast<int32_t>(TrackType::TAGGED));
321 Jump(&exit);
322 }
323 Bind(&isDouble);
324 {
325 newTrackType = Int32(static_cast<int32_t>(TrackType::DOUBLE));
326 Jump(&exit);
327 }
328 }
329 Bind(&exit);
330 auto ret = *newTrackType;
331 env->SubCfgExit();
332 return ret;
333 }
334 } // namespace panda::ecmascript::kungfu
335