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/ic_stub_builder.h"
16
17 #include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h"
18 #include "ecmascript/compiler/stub_builder-inl.h"
19
20 namespace panda::ecmascript::kungfu {
21 template<ICStubType type>
NamedICAccessor(Variable * cachedHandler,Label * tryICHandler)22 void ICStubBuilder::NamedICAccessor(Variable* cachedHandler, Label *tryICHandler)
23 {
24 auto env = GetEnvironment();
25 Label receiverIsHeapObject(env);
26 Label receiverNotHeapObject(env);
27 Label tryIC(env);
28 if constexpr (type == ICStubType::LOAD) {
29 BRANCH(TaggedIsHeapObject(receiver_), &receiverIsHeapObject, &receiverNotHeapObject);
30 } else {
31 BRANCH(TaggedIsHeapObject(receiver_), &receiverIsHeapObject, slowPath_);
32 }
33 Bind(&receiverIsHeapObject);
34 {
35 BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
36 Bind(&tryIC);
37 {
38 Label isHeapObject(env);
39 Label notHeapObject(env);
40 GateRef firstValue = GetValueFromTaggedArray(
41 profileTypeInfo_, slotId_);
42 BRANCH(TaggedIsHeapObject(firstValue), &isHeapObject, ¬HeapObject);
43 Bind(&isHeapObject);
44 {
45 GateRef secondValue = GetValueFromTaggedArray(profileTypeInfo_, Int32Add(slotId_, Int32(1)));
46 cachedHandler->WriteVariable(secondValue);
47 Label tryPoly(env);
48 GateRef hclass = LoadHClass(receiver_);
49 BRANCH(Equal(LoadObjectFromWeakRef(firstValue), hclass),
50 tryICHandler,
51 &tryPoly);
52 Bind(&tryPoly);
53 {
54 cachedHandler->WriteVariable(CheckPolyHClass(firstValue, hclass));
55 BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), slowPath_, tryICHandler);
56 }
57 }
58 Bind(¬HeapObject);
59 {
60 BRANCH(TaggedIsUndefined(firstValue), slowPath_, tryFastPath_);
61 }
62 }
63 }
64 if constexpr (type == ICStubType::STORE) {
65 return;
66 }
67 Bind(&receiverNotHeapObject);
68 {
69 Label tryNumber(env);
70 Label profileNotUndefined(env);
71 BRANCH(TaggedIsNumber(receiver_), &tryNumber, slowPath_);
72 Bind(&tryNumber);
73 {
74 BRANCH(TaggedIsUndefined(profileTypeInfo_), slowPath_, &profileNotUndefined);
75 Bind(&profileNotUndefined);
76 {
77 GateRef firstValue = GetValueFromTaggedArray(profileTypeInfo_, slotId_);
78 GateRef secondValue = GetValueFromTaggedArray(profileTypeInfo_, Int32Add(slotId_, Int32(1)));
79 cachedHandler->WriteVariable(secondValue);
80 Label isHeapObject(env);
81 BRANCH(TaggedIsHeapObject(firstValue), &isHeapObject, slowPath_)
82 Bind(&isHeapObject);
83 {
84 GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit()));
85 GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue_, glueGlobalEnvOffset);
86 auto numberFunction = GetGlobalEnvValue(VariableType::JS_ANY(),
87 glueGlobalEnv, GlobalEnv::NUMBER_FUNCTION_INDEX);
88 GateRef ctorProtoOrHC =
89 Load(VariableType::JS_POINTER(), numberFunction,
90 IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET));
91 BRANCH(Equal(LoadObjectFromWeakRef(firstValue), ctorProtoOrHC), tryICHandler, slowPath_);
92 }
93 }
94 }
95 }
96 }
97
ValuedICAccessor(Variable * cachedHandler,Label * tryICHandler,Label * tryElementIC)98 void ICStubBuilder::ValuedICAccessor(Variable* cachedHandler, Label *tryICHandler, Label* tryElementIC)
99 {
100 auto env = GetEnvironment();
101 Label receiverIsHeapObject(env);
102
103 BRANCH(TaggedIsHeapObject(receiver_), &receiverIsHeapObject, slowPath_);
104 Bind(&receiverIsHeapObject);
105 {
106 Label tryIC(env);
107 BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
108 Bind(&tryIC);
109 {
110 Label isHeapObject(env);
111 Label notHeapObject(env);
112 GateRef firstValue = GetValueFromTaggedArray(
113 profileTypeInfo_, slotId_);
114 BRANCH(TaggedIsHeapObject(firstValue), &isHeapObject, ¬HeapObject);
115 Bind(&isHeapObject);
116 {
117 Label tryPoly(env);
118 Label tryWithElementPoly(env);
119 GateRef hclass = LoadHClass(receiver_);
120 BRANCH(Equal(LoadObjectFromWeakRef(firstValue), hclass),
121 tryElementIC,
122 &tryPoly);
123 Bind(&tryPoly);
124 {
125 Label firstIsKey(env);
126 BRANCH(Int64Equal(firstValue, propKey_), &firstIsKey, &tryWithElementPoly);
127 Bind(&firstIsKey);
128 {
129 GateRef handler = CheckPolyHClass(cachedHandler->ReadVariable(), hclass);
130 cachedHandler->WriteVariable(handler);
131 BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), slowPath_, tryICHandler);
132 }
133 Bind(&tryWithElementPoly);
134 {
135 Label checkSecond(env);
136 Label checkPoly(env);
137 BRANCH(TaggedIsWeak(firstValue), slowPath_, &checkSecond);
138 Bind(&checkSecond);
139 {
140 BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), &checkPoly, slowPath_);
141 }
142 Bind(&checkPoly);
143 {
144 cachedHandler->WriteVariable(CheckPolyHClass(firstValue, hclass));
145 BRANCH(TaggedIsHole(cachedHandler->ReadVariable()), slowPath_, tryElementIC);
146 }
147 }
148 }
149 }
150 Bind(¬HeapObject);
151 {
152 BRANCH(TaggedIsUndefined(firstValue), slowPath_, tryFastPath_);
153 }
154 }
155 }
156 }
157
LoadICByName(Variable * result,Label * tryFastPath,Label * slowPath,Label * success,ProfileOperation callback)158 void ICStubBuilder::LoadICByName(
159 Variable *result, Label *tryFastPath, Label *slowPath, Label *success, ProfileOperation callback)
160 {
161 auto env = GetEnvironment();
162 Label loadWithHandler(env);
163
164 SetLabels(tryFastPath, slowPath, success);
165 DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), Undefined());
166 NamedICAccessor<ICStubType::LOAD>(&cachedHandler, &loadWithHandler);
167 Bind(&loadWithHandler);
168 {
169 GateRef ret = LoadICWithHandler(glue_, receiver_, receiver_, *cachedHandler, callback);
170 result->WriteVariable(ret);
171 BRANCH(TaggedIsHole(ret), slowPath_, success_);
172 }
173 }
174
StoreICByName(Variable * result,Label * tryFastPath,Label * slowPath,Label * success)175 void ICStubBuilder::StoreICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
176 {
177 auto env = GetEnvironment();
178 Label storeWithHandler(env);
179
180 SetLabels(tryFastPath, slowPath, success);
181 GateRef secondValue = GetValueFromTaggedArray(
182 profileTypeInfo_, Int32Add(slotId_, Int32(1)));
183 DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), secondValue);
184 NamedICAccessor<ICStubType::STORE>(&cachedHandler, &storeWithHandler);
185 Bind(&storeWithHandler);
186 {
187 GateRef ret = StoreICWithHandler(glue_, receiver_, receiver_, value_, *cachedHandler, callback_);
188 result->WriteVariable(ret);
189 BRANCH(TaggedIsHole(ret), slowPath_, success_);
190 }
191 }
192
LoadICByValue(Variable * result,Label * tryFastPath,Label * slowPath,Label * success,ProfileOperation callback)193 void ICStubBuilder::LoadICByValue(
194 Variable *result, Label *tryFastPath, Label *slowPath, Label *success, ProfileOperation callback)
195 {
196 auto env = GetEnvironment();
197 Label loadWithHandler(env);
198 Label loadElement(env);
199 Label handlerInfoIsElement(env);
200 Label handlerInfoNotElement(env);
201 Label handlerInfoIsStringElement(env);
202 Label handlerInfoNotStringElement(env);
203 Label handlerInfoIsTypedArrayElement(env);
204 Label exit(env);
205
206 SetLabels(tryFastPath, slowPath, success);
207 GateRef secondValue = GetValueFromTaggedArray(
208 profileTypeInfo_, Int32Add(slotId_, Int32(1)));
209 DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), secondValue);
210 DEFVARIABLE(ret, VariableType::JS_ANY(), secondValue);
211
212 ValuedICAccessor(&cachedHandler, &loadWithHandler, &loadElement);
213 Bind(&loadElement);
214 {
215 GateRef handlerInfo = GetInt64OfTInt(*cachedHandler);
216 BRANCH(IsElement(handlerInfo), &handlerInfoIsElement, &handlerInfoNotElement);
217 Bind(&handlerInfoIsElement);
218 {
219 ret = LoadElement(glue_, receiver_, propKey_);
220 Jump(&exit);
221 }
222 Bind(&handlerInfoNotElement);
223 {
224 BRANCH(IsStringElement(handlerInfo), &handlerInfoIsStringElement, &handlerInfoNotStringElement);
225 Bind(&handlerInfoIsStringElement);
226 {
227 ret = LoadStringElement(glue_, receiver_, propKey_);
228 Jump(&exit);
229 }
230 Bind(&handlerInfoNotStringElement);
231 {
232 BRANCH(IsTypedArrayElement(handlerInfo), &handlerInfoIsTypedArrayElement, &exit);
233 Bind(&handlerInfoIsTypedArrayElement);
234 {
235 GateRef hclass = LoadHClass(receiver_);
236 GateRef jsType = GetObjectType(hclass);
237 BuiltinsTypedArrayStubBuilder typedArrayBuilder(reinterpret_cast<StubBuilder*>(this));
238 ret = typedArrayBuilder.LoadTypedArrayElement(glue_, receiver_, propKey_, jsType);
239 Jump(&exit);
240 }
241 }
242 }
243 }
244 Bind(&loadWithHandler);
245 {
246 ret = LoadICWithHandler(glue_, receiver_, receiver_, *cachedHandler, callback);
247 Jump(&exit);
248 }
249 Bind(&exit);
250 result->WriteVariable(*ret);
251 BRANCH(TaggedIsHole(*ret), slowPath_, success_);
252 }
253
StoreICByValue(Variable * result,Label * tryFastPath,Label * slowPath,Label * success)254 void ICStubBuilder::StoreICByValue(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
255 {
256 auto env = GetEnvironment();
257 Label storeWithHandler(env);
258 Label storeElement(env);
259 SetLabels(tryFastPath, slowPath, success);
260 GateRef secondValue = GetValueFromTaggedArray(
261 profileTypeInfo_, Int32Add(slotId_, Int32(1)));
262 DEFVARIABLE(cachedHandler, VariableType::JS_ANY(), secondValue);
263 ValuedICAccessor(&cachedHandler, &storeWithHandler, &storeElement);
264 Bind(&storeElement);
265 {
266 GateRef ret = ICStoreElement(glue_, receiver_, propKey_, value_, *cachedHandler,
267 true, profileTypeInfo_, Int32Add(slotId_, Int32(1)));
268 result->WriteVariable(ret);
269 BRANCH(TaggedIsHole(ret), slowPath_, success_);
270 }
271 Bind(&storeWithHandler);
272 {
273 GateRef ret = StoreICWithHandler(glue_, receiver_, receiver_, value_, *cachedHandler, callback_);
274 result->WriteVariable(ret);
275 BRANCH(TaggedIsHole(ret), slowPath_, success_);
276 }
277 }
278
TryLoadGlobalICByName(Variable * result,Label * tryFastPath,Label * slowPath,Label * success)279 void ICStubBuilder::TryLoadGlobalICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
280 {
281 auto env = GetEnvironment();
282 Label tryIC(env);
283
284 SetLabels(tryFastPath, slowPath, success);
285 BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
286 Bind(&tryIC);
287 {
288 GateRef handler = GetValueFromTaggedArray(profileTypeInfo_, slotId_);
289 Label isHeapObject(env);
290 BRANCH(TaggedIsHeapObject(handler), &isHeapObject, slowPath_);
291 Bind(&isHeapObject);
292 {
293 GateRef ret = LoadGlobal(handler);
294 result->WriteVariable(ret);
295 BRANCH(TaggedIsHole(ret), slowPath_, success_);
296 }
297 }
298 }
299
TryStoreGlobalICByName(Variable * result,Label * tryFastPath,Label * slowPath,Label * success)300 void ICStubBuilder::TryStoreGlobalICByName(Variable* result, Label* tryFastPath, Label *slowPath, Label *success)
301 {
302 auto env = GetEnvironment();
303 Label tryIC(env);
304
305 SetLabels(tryFastPath, slowPath, success);
306 BRANCH(TaggedIsUndefined(profileTypeInfo_), tryFastPath_, &tryIC);
307 Bind(&tryIC);
308 {
309 GateRef handler = GetValueFromTaggedArray(profileTypeInfo_, slotId_);
310 Label isHeapObject(env);
311 BRANCH(TaggedIsHeapObject(handler), &isHeapObject, slowPath_);
312 Bind(&isHeapObject);
313 {
314 GateRef ret = StoreGlobal(glue_, value_, handler);
315 result->WriteVariable(ret);
316 BRANCH(TaggedIsHole(ret), slowPath_, success_);
317 }
318 }
319 }
320 } // namespace panda::ecmascript::kungfu
321