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, ¬Hole);
44 Bind(¬Hole);
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), ¬FoundInRecord, &foundInRecord);
262 Bind(&foundInRecord);
263 {
264 result = Load(VariableType::JS_ANY(), record, IntPtr(PropertyBox::VALUE_OFFSET));
265 Jump(&exit);
266 }
267 Bind(¬FoundInRecord);
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), ¬FoundInRecord, &foundInRecord);
311 Bind(&foundInRecord);
312 {
313 result = CallRuntime(glue, RTSTUB_ID(TryUpdateGlobalRecord), { propKey, value });
314 Jump(&exit);
315 }
316 Bind(¬FoundInRecord);
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), ¬FoundInGlobal, &isFoundInGlobal);
323 Bind(&isFoundInGlobal);
324 {
325 result = CallRuntime(glue, RTSTUB_ID(StGlobalVar), { propKey, value });
326 Jump(&exit);
327 }
328 Bind(¬FoundInGlobal);
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