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