• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "ecmascript/compiler/access_object_stub_builder.h"
16 #include "ecmascript/compiler/ic_stub_builder.h"
17 #include "ecmascript/compiler/interpreter_stub-inl.h"
18 #include "ecmascript/compiler/rt_call_signature.h"
19 #include "ecmascript/compiler/stub_builder-inl.h"
20 #include "ecmascript/ic/profile_type_info.h"
21 
22 namespace panda::ecmascript::kungfu {
LoadObjByName(GateRef glue,GateRef receiver,GateRef prop,const StringIdInfo & info,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)23 GateRef AccessObjectStubBuilder::LoadObjByName(GateRef glue, GateRef receiver, GateRef prop, const StringIdInfo &info,
24                                                GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
25 {
26     auto env = GetEnvironment();
27     Label entry(env);
28     env->SubCfgEntry(&entry);
29     Label exit(env);
30     Label tryFastPath(env);
31     Label slowPath(env);
32 
33     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
34     GateRef value = 0;
35     ICStubBuilder builder(this);
36     builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
37     builder.LoadICByName(&result, &tryFastPath, &slowPath, &exit, callback);
38     Bind(&tryFastPath);
39     {
40         GateRef propKey = ResolvePropKey(glue, prop, info);
41         result = GetPropertyByName(glue, receiver, propKey, callback);
42         Label notHole(env);
43         Branch(TaggedIsHole(*result), &slowPath, &notHole);
44         Bind(&notHole);
45         {
46             callback.ProfileObjLayoutByLoad(receiver);
47             Jump(&exit);
48         }
49     }
50     Bind(&slowPath);
51     {
52         GateRef propKey = ResolvePropKey(glue, prop, info);
53         result = CallRuntime(glue, RTSTUB_ID(LoadICByName),
54                              { profileTypeInfo, receiver, propKey, IntToTaggedInt(slotId) });
55         callback.ProfileObjLayoutByLoad(receiver);
56         Jump(&exit);
57     }
58     Bind(&exit);
59     auto ret = *result;
60     env->SubCfgExit();
61     return ret;
62 }
63 
64 // Used for deprecated bytecodes which will not support ic
DeprecatedLoadObjByName(GateRef glue,GateRef receiver,GateRef propKey)65 GateRef AccessObjectStubBuilder::DeprecatedLoadObjByName(GateRef glue, GateRef receiver, GateRef propKey)
66 {
67     auto env = GetEnvironment();
68     Label entry(env);
69     env->SubCfgEntry(&entry);
70     Label exit(env);
71     Label fastPath(env);
72     Label slowPath(env);
73 
74     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
75     Branch(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
76     Bind(&fastPath);
77     {
78         result = GetPropertyByName(glue, receiver, propKey, ProfileOperation());
79         Branch(TaggedIsHole(*result), &slowPath, &exit);
80     }
81     Bind(&slowPath);
82     {
83         result = CallRuntime(glue, RTSTUB_ID(LoadICByName),
84             { Undefined(), receiver, propKey, IntToTaggedInt(Int32(0xFF)) });  // 0xFF: invalid slot id
85         Jump(&exit);
86     }
87     Bind(&exit);
88     auto ret = *result;
89     env->SubCfgExit();
90     return ret;
91 }
92 
StoreObjByName(GateRef glue,GateRef receiver,GateRef prop,const StringIdInfo & info,GateRef value,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)93 GateRef AccessObjectStubBuilder::StoreObjByName(GateRef glue, GateRef receiver, GateRef prop, const StringIdInfo &info,
94                                                 GateRef value, GateRef profileTypeInfo, GateRef slotId,
95                                                 ProfileOperation callback)
96 {
97     auto env = GetEnvironment();
98     Label entry(env);
99     env->SubCfgEntry(&entry);
100     Label exit(env);
101     Label tryFastPath(env);
102     Label slowPath(env);
103 
104     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
105     ICStubBuilder builder(this);
106     builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, callback);
107     builder.StoreICByName(&result, &tryFastPath, &slowPath, &exit);
108     Bind(&tryFastPath);
109     {
110         GateRef propKey = ResolvePropKey(glue, prop, info);
111         result = SetPropertyByName(glue, receiver, propKey, value, false, callback);
112         Branch(TaggedIsHole(*result), &slowPath, &exit);
113     }
114     Bind(&slowPath);
115     {
116         GateRef propKey = ResolvePropKey(glue, prop, info);
117         result = CallRuntime(glue, RTSTUB_ID(StoreICByName),
118             { profileTypeInfo, receiver, propKey, value, IntToTaggedInt(slotId) });
119         callback.ProfileObjLayoutByStore(receiver);
120         Jump(&exit);
121     }
122 
123     Bind(&exit);
124     auto ret = *result;
125     env->SubCfgExit();
126     return ret;
127 }
128 
ResolvePropKey(GateRef glue,GateRef prop,const StringIdInfo & info)129 GateRef AccessObjectStubBuilder::ResolvePropKey(GateRef glue, GateRef prop, const StringIdInfo &info)
130 {
131     if (jsFunc_ != Circuit::NullGate()) {
132         GateRef constpool = GetConstPoolFromFunction(jsFunc_);
133         return GetStringFromConstPool(glue, constpool, ChangeIntPtrToInt32(prop));
134     }
135     if (!info.IsValid()) {
136         return prop;
137     }
138     ASSERT(info.IsValid());
139     InterpreterToolsStubBuilder builder(GetCallSignature(), GetEnvironment());
140     GateRef stringId = builder.GetStringId(info);
141     return GetStringFromConstPool(glue, info.constpool, stringId);
142 }
143 
LoadObjByValue(GateRef glue,GateRef receiver,GateRef key,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)144 GateRef AccessObjectStubBuilder::LoadObjByValue(GateRef glue, GateRef receiver, GateRef key, GateRef profileTypeInfo,
145                                                 GateRef slotId, ProfileOperation callback)
146 {
147     auto env = GetEnvironment();
148     Label entry(env);
149     env->SubCfgEntry(&entry);
150     Label exit(env);
151     Label tryFastPath(env);
152     Label slowPath(env);
153 
154     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
155     GateRef value = 0;
156     ICStubBuilder builder(this);
157     builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, key);
158     builder.LoadICByValue(&result, &tryFastPath, &slowPath, &exit, callback);
159     Bind(&tryFastPath);
160     {
161         result = GetPropertyByValue(glue, receiver, key, callback);
162         Branch(TaggedIsHole(*result), &slowPath, &exit);
163     }
164     Bind(&slowPath);
165     {
166         result = CallRuntime(glue, RTSTUB_ID(LoadICByValue),
167             { profileTypeInfo, receiver, key, IntToTaggedInt(slotId) });
168         callback.ProfileObjLayoutByLoad(receiver);
169         Jump(&exit);
170     }
171     Bind(&exit);
172     auto ret = *result;
173     env->SubCfgExit();
174     return ret;
175 }
176 
177 // Used for deprecated bytecodes which will not support ic
DeprecatedLoadObjByValue(GateRef glue,GateRef receiver,GateRef key)178 GateRef AccessObjectStubBuilder::DeprecatedLoadObjByValue(GateRef glue, GateRef receiver, GateRef key)
179 {
180     auto env = GetEnvironment();
181     Label entry(env);
182     env->SubCfgEntry(&entry);
183     Label exit(env);
184     Label fastPath(env);
185     Label slowPath(env);
186 
187     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
188     Branch(TaggedIsHeapObject(receiver), &fastPath, &slowPath);
189     Bind(&fastPath);
190     {
191         result = GetPropertyByValue(glue, receiver, key, ProfileOperation());
192         Branch(TaggedIsHole(*result), &slowPath, &exit);
193     }
194     Bind(&slowPath);
195     {
196         result = CallRuntime(glue, RTSTUB_ID(LoadICByValue),
197             { Undefined(), receiver, key, IntToTaggedInt(Int32(0xFF)) });  // 0xFF: invalied slot id
198         Jump(&exit);
199     }
200     Bind(&exit);
201     auto ret = *result;
202     env->SubCfgExit();
203     return ret;
204 }
205 
StoreObjByValue(GateRef glue,GateRef receiver,GateRef key,GateRef value,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)206 GateRef AccessObjectStubBuilder::StoreObjByValue(GateRef glue, GateRef receiver, GateRef key, GateRef value,
207                                                  GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
208 {
209     auto env = GetEnvironment();
210     Label entry(env);
211     env->SubCfgEntry(&entry);
212     Label exit(env);
213     Label tryFastPath(env);
214     Label slowPath(env);
215 
216     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
217     ICStubBuilder builder(this);
218     builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId, key, callback);
219     builder.StoreICByValue(&result, &tryFastPath, &slowPath, &exit);
220     Bind(&tryFastPath);
221     {
222         result = SetPropertyByValue(glue, receiver, key, value, false, callback);
223         Branch(TaggedIsHole(*result), &slowPath, &exit);
224     }
225     Bind(&slowPath);
226     {
227         result = CallRuntime(glue, RTSTUB_ID(StoreICByValue),
228             { profileTypeInfo, receiver, key, value, IntToTaggedInt(slotId) });
229         callback.ProfileObjLayoutByStore(receiver);
230         Jump(&exit);
231     }
232     Bind(&exit);
233     auto ret = *result;
234     env->SubCfgExit();
235     return ret;
236 }
237 
TryLoadGlobalByName(GateRef glue,GateRef prop,const StringIdInfo & info,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)238 GateRef AccessObjectStubBuilder::TryLoadGlobalByName(GateRef glue, GateRef prop, const StringIdInfo &info,
239                                                      GateRef profileTypeInfo, GateRef slotId,
240                                                      ProfileOperation callback)
241 {
242     auto env = GetEnvironment();
243     Label entry(env);
244     env->SubCfgEntry(&entry);
245     Label exit(env);
246     Label tryFastPath(env);
247     Label slowPath(env);
248 
249     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
250     GateRef receiver = 0;
251     GateRef value = 0;
252     ICStubBuilder builder(this);
253     builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
254     builder.TryLoadGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
255     Bind(&tryFastPath);
256     {
257         GateRef propKey = ResolvePropKey(glue, prop, info);
258         GateRef record = LdGlobalRecord(glue, propKey);
259         Label foundInRecord(env);
260         Label notFoundInRecord(env);
261         Branch(TaggedIsUndefined(record), &notFoundInRecord, &foundInRecord);
262         Bind(&foundInRecord);
263         {
264             result = Load(VariableType::JS_ANY(), record, IntPtr(PropertyBox::VALUE_OFFSET));
265             Jump(&exit);
266         }
267         Bind(&notFoundInRecord);
268         {
269             GateRef globalObject = GetGlobalObject(glue);
270             result = GetGlobalOwnProperty(glue, globalObject, propKey, callback);
271             Branch(TaggedIsHole(*result), &slowPath, &exit);
272         }
273     }
274     Bind(&slowPath);
275     {
276         GateRef propKey = ResolvePropKey(glue, prop, info);
277         result = CallRuntime(glue, RTSTUB_ID(TryLdGlobalICByName),
278                              { profileTypeInfo, propKey, IntToTaggedInt(slotId) });
279         Jump(&exit);
280     }
281 
282     Bind(&exit);
283     auto ret = *result;
284     env->SubCfgExit();
285     return ret;
286 }
287 
TryStoreGlobalByName(GateRef glue,GateRef prop,const StringIdInfo & info,GateRef value,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)288 GateRef AccessObjectStubBuilder::TryStoreGlobalByName(GateRef glue, GateRef prop, const StringIdInfo &info,
289                                                       GateRef value, GateRef profileTypeInfo, GateRef slotId,
290                                                       ProfileOperation callback)
291 {
292     auto env = GetEnvironment();
293     Label entry(env);
294     env->SubCfgEntry(&entry);
295     Label exit(env);
296     Label tryFastPath(env);
297     Label slowPath(env);
298 
299     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
300     GateRef receiver = 0;
301     ICStubBuilder builder(this);
302     builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
303     builder.TryStoreGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
304     Bind(&tryFastPath);
305     {
306         GateRef propKey = ResolvePropKey(glue, prop, info);
307         GateRef record = LdGlobalRecord(glue, propKey);
308         Label foundInRecord(env);
309         Label notFoundInRecord(env);
310         Branch(TaggedIsUndefined(record), &notFoundInRecord, &foundInRecord);
311         Bind(&foundInRecord);
312         {
313             result = CallRuntime(glue, RTSTUB_ID(TryUpdateGlobalRecord), { propKey, value });
314             Jump(&exit);
315         }
316         Bind(&notFoundInRecord);
317         {
318             GateRef globalObject = GetGlobalObject(glue);
319             result = GetGlobalOwnProperty(glue, globalObject, propKey, callback);
320             Label isFoundInGlobal(env);
321             Label notFoundInGlobal(env);
322             Branch(TaggedIsHole(*result), &notFoundInGlobal, &isFoundInGlobal);
323             Bind(&isFoundInGlobal);
324             {
325                 result = CallRuntime(glue, RTSTUB_ID(StGlobalVar), { propKey, value });
326                 Jump(&exit);
327             }
328             Bind(&notFoundInGlobal);
329             {
330                 result = CallRuntime(glue, RTSTUB_ID(ThrowReferenceError), { propKey });
331                 Jump(&exit);
332             }
333         }
334     }
335     Bind(&slowPath);
336     {
337         GateRef propKey = ResolvePropKey(glue, prop, info);
338         GateRef globalObject = GetGlobalObject(glue);
339         result = CallRuntime(glue, RTSTUB_ID(StoreMiss),
340                              { profileTypeInfo, globalObject, propKey, value, IntToTaggedInt(slotId),
341                                IntToTaggedInt(Int32(static_cast<int>(ICKind::NamedGlobalTryStoreIC))) });
342         Jump(&exit);
343     }
344 
345     Bind(&exit);
346     auto ret = *result;
347     env->SubCfgExit();
348     return ret;
349 }
350 
LoadGlobalVar(GateRef glue,GateRef prop,const StringIdInfo & info,GateRef profileTypeInfo,GateRef slotId,ProfileOperation callback)351 GateRef AccessObjectStubBuilder::LoadGlobalVar(GateRef glue, GateRef prop, const StringIdInfo &info,
352                                                GateRef profileTypeInfo, GateRef slotId, ProfileOperation callback)
353 {
354     auto env = GetEnvironment();
355     Label entry(env);
356     env->SubCfgEntry(&entry);
357     Label exit(env);
358     Label tryFastPath(env);
359     Label slowPath(env);
360 
361     DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
362     GateRef receiver = 0;
363     GateRef value = 0;
364     ICStubBuilder builder(this);
365     builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
366     builder.TryLoadGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
367     Bind(&tryFastPath);
368     {
369         GateRef globalObject = GetGlobalObject(glue);
370         GateRef propKey = ResolvePropKey(glue, prop, info);
371         result = GetGlobalOwnProperty(glue, globalObject, propKey, callback);
372         Branch(TaggedIsHole(*result), &slowPath, &exit);
373     }
374     Bind(&slowPath);
375     {
376         GateRef globalObject = GetGlobalObject(glue);
377         GateRef propKey = ResolvePropKey(glue, prop, info);
378         result = CallRuntime(glue, RTSTUB_ID(LdGlobalICVar),
379                              { globalObject, propKey, profileTypeInfo, IntToTaggedInt(slotId) });
380         Jump(&exit);
381     }
382 
383     Bind(&exit);
384     auto ret = *result;
385     env->SubCfgExit();
386     return ret;
387 }
388 
StoreGlobalVar(GateRef glue,GateRef prop,const StringIdInfo & info,GateRef value,GateRef profileTypeInfo,GateRef slotId)389 GateRef AccessObjectStubBuilder::StoreGlobalVar(GateRef glue, GateRef prop, const StringIdInfo &info,
390                                                 GateRef value, GateRef profileTypeInfo, GateRef slotId)
391 {
392     auto env = GetEnvironment();
393     Label entry(env);
394     env->SubCfgEntry(&entry);
395     Label exit(env);
396     Label tryFastPath(env);
397     Label slowPath(env);
398 
399     DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
400     GateRef receiver = 0;
401     ICStubBuilder builder(this);
402     builder.SetParameters(glue, receiver, profileTypeInfo, value, slotId);
403     builder.TryStoreGlobalICByName(&result, &tryFastPath, &slowPath, &exit);
404     Bind(&tryFastPath);
405     {
406         GateRef propKey = ResolvePropKey(glue, prop, info);
407         // IR later
408         result = CallRuntime(glue, RTSTUB_ID(StGlobalVar), { propKey, value });
409         Jump(&exit);
410     }
411     Bind(&slowPath);
412     {
413         GateRef propKey = ResolvePropKey(glue, prop, info);
414         GateRef globalObject = GetGlobalObject(glue);
415         result = CallRuntime(glue, RTSTUB_ID(StoreMiss),
416                              { profileTypeInfo, globalObject, propKey, value, IntToTaggedInt(slotId),
417                                IntToTaggedInt(Int32(static_cast<int>(ICKind::NamedGlobalStoreIC))) });
418         Jump(&exit);
419     }
420 
421     Bind(&exit);
422     auto ret = *result;
423     env->SubCfgExit();
424     return ret;
425 }
426 }  // namespace panda::ecmascript::kungfu
427