• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notInt);
308     Bind(&isInt);
309     {
310         newTrackType = Int32(static_cast<int32_t>(TrackType::INT));
311         Jump(&exit);
312     }
313     Bind(&notInt);
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