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/typed_array_stub_builder.h"
17
18 #include "ecmascript/base/typed_array_helper.h"
19 #include "ecmascript/byte_array.h"
20 #include "ecmascript/compiler/new_object_stub_builder.h"
21
22 namespace panda::ecmascript::kungfu {
IsDetachedBuffer(GateRef buffer)23 GateRef TypedArrayStubBuilder::IsDetachedBuffer(GateRef buffer)
24 {
25 auto env = GetEnvironment();
26 Label entryPass(env);
27 env->SubCfgEntry(&entryPass);
28 Label isNull(env);
29 Label exit(env);
30 Label isByteArray(env);
31 Label notByteArray(env);
32 DEFVARIABLE(result, VariableType::BOOL(), False());
33 Branch(IsByteArray(buffer), &isByteArray, ¬ByteArray);
34 Bind(&isByteArray);
35 {
36 Jump(&exit);
37 }
38 Bind(¬ByteArray);
39 {
40 GateRef dataSlot = GetArrayBufferData(buffer);
41 Branch(TaggedIsNull(dataSlot), &isNull, &exit);
42 Bind(&isNull);
43 {
44 result = True();
45 Jump(&exit);
46 }
47 }
48 Bind(&exit);
49 auto ret = *result;
50 env->SubCfgExit();
51 return ret;
52 }
53
GetDataPointFromBuffer(GateRef arrBuf)54 GateRef TypedArrayStubBuilder::GetDataPointFromBuffer(GateRef arrBuf)
55 {
56 auto env = GetEnvironment();
57 Label entryPass(env);
58 env->SubCfgEntry(&entryPass);
59 Label isNull(env);
60 Label exit(env);
61 Label isByteArray(env);
62 Label notByteArray(env);
63 DEFVARIABLE(result, VariableType::JS_ANY(), arrBuf);
64 Branch(IsByteArray(arrBuf), &isByteArray, ¬ByteArray);
65 Bind(&isByteArray);
66 {
67 result = PtrAdd(*result, IntPtr(ByteArray::DATA_OFFSET));
68 Jump(&exit);
69 }
70 Bind(¬ByteArray);
71 {
72 GateRef data = GetArrayBufferData(arrBuf);
73 result = GetExternalPointer(data);
74 Jump(&exit);
75 }
76 Bind(&exit);
77 auto ret = *result;
78 env->SubCfgExit();
79 return ret;
80 }
81
CheckTypedArrayIndexInRange(GateRef array,GateRef index)82 GateRef TypedArrayStubBuilder::CheckTypedArrayIndexInRange(GateRef array, GateRef index)
83 {
84 auto env = GetEnvironment();
85 Label entryPass(env);
86 env->SubCfgEntry(&entryPass);
87 DEFVARIABLE(result, VariableType::BOOL(), False());
88 Label exit(env);
89 Label indexIsvalid(env);
90 Label indexNotLessZero(env);
91 Branch(Int64LessThan(index, Int64(0)), &exit, &indexNotLessZero);
92 Bind(&indexNotLessZero);
93 {
94 GateRef arrLen = GetArrayLength(array);
95 Branch(Int64GreaterThanOrEqual(index, ZExtInt32ToInt64(arrLen)), &exit, &indexIsvalid);
96 Bind(&indexIsvalid);
97 {
98 result = True();
99 Jump(&exit);
100 }
101 }
102 Bind(&exit);
103 auto ret = *result;
104 env->SubCfgExit();
105 return ret;
106 }
107
LoadTypedArrayElement(GateRef glue,GateRef array,GateRef key,GateRef jsType)108 GateRef TypedArrayStubBuilder::LoadTypedArrayElement(GateRef glue, GateRef array, GateRef key, GateRef jsType)
109 {
110 auto env = GetEnvironment();
111 Label entryPass(env);
112 env->SubCfgEntry(&entryPass);
113 DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
114 Label exit(env);
115 Label notDetached(env);
116 Label indexIsvalid(env);
117 Label slowPath(env);
118 GateRef buffer = GetViewedArrayBuffer(array);
119 Branch(IsDetachedBuffer(buffer), &exit, ¬Detached);
120 Bind(¬Detached);
121 {
122 GateRef index = TryToElementsIndex(glue, key);
123 Branch(CheckTypedArrayIndexInRange(array, index), &indexIsvalid, &exit);
124 Bind(&indexIsvalid);
125 {
126 GateRef offset = GetByteOffset(array);
127 result = GetValueFromBuffer(buffer, TruncInt64ToInt32(index), offset, jsType);
128 Branch(TaggedIsNumber(*result), &exit, &slowPath);
129 }
130 Bind(&slowPath);
131 {
132 result = CallRuntime(glue, RTSTUB_ID(GetTypeArrayPropertyByIndex),
133 { array, IntToTaggedInt(index), IntToTaggedInt(jsType) });
134 Jump(&exit);
135 }
136 }
137 Bind(&exit);
138 auto ret = *result;
139 env->SubCfgExit();
140 return ret;
141 }
142
StoreTypedArrayElement(GateRef glue,GateRef array,GateRef index,GateRef value,GateRef jsType)143 GateRef TypedArrayStubBuilder::StoreTypedArrayElement(GateRef glue, GateRef array, GateRef index, GateRef value,
144 GateRef jsType)
145 {
146 auto env = GetEnvironment();
147 Label entryPass(env);
148 env->SubCfgEntry(&entryPass);
149 DEFVARIABLE(result, VariableType::JS_ANY(), Hole());
150 Label exit(env);
151 Label notDetached(env);
152 Label indexIsvalid(env);
153 GateRef buffer = GetViewedArrayBuffer(array);
154 Branch(IsDetachedBuffer(buffer), &exit, ¬Detached);
155 Bind(¬Detached);
156 {
157 Branch(CheckTypedArrayIndexInRange(array, index), &indexIsvalid, &exit);
158 Bind(&indexIsvalid);
159 {
160 result = CallRuntime(glue, RTSTUB_ID(SetTypeArrayPropertyByIndex),
161 { array, IntToTaggedInt(index), value, IntToTaggedInt(jsType) });
162 Jump(&exit);
163 }
164 }
165 Bind(&exit);
166 auto ret = *result;
167 env->SubCfgExit();
168 return ret;
169 }
170
FastGetPropertyByIndex(GateRef glue,GateRef array,GateRef index,GateRef jsType)171 GateRef TypedArrayStubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef array, GateRef index, GateRef jsType)
172 {
173 auto env = GetEnvironment();
174 Label entryPass(env);
175 env->SubCfgEntry(&entryPass);
176 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
177 Label exit(env);
178 Label isDetached(env);
179 Label notDetached(env);
180 Label slowPath(env);
181 Label indexIsvalid(env);
182
183 GateRef buffer = GetViewedArrayBuffer(array);
184 Branch(IsDetachedBuffer(buffer), &isDetached, ¬Detached);
185 Bind(&isDetached);
186 {
187 Jump(&slowPath);
188 }
189 Bind(¬Detached);
190 {
191 GateRef arrLen = GetArrayLength(array);
192 Branch(Int32GreaterThanOrEqual(index, arrLen), &exit, &indexIsvalid);
193 Bind(&indexIsvalid);
194 {
195 GateRef offset = GetByteOffset(array);
196 result = GetValueFromBuffer(buffer, index, offset, jsType);
197 Branch(TaggedIsNumber(*result), &exit, &slowPath);
198 }
199 }
200 Bind(&slowPath);
201 {
202 result = CallRuntime(glue, RTSTUB_ID(GetTypeArrayPropertyByIndex),
203 { array, IntToTaggedInt(index), IntToTaggedInt(jsType)});
204 Jump(&exit);
205 }
206 Bind(&exit);
207 auto ret = *result;
208 env->SubCfgExit();
209 return ret;
210 }
211
FastCopyElementToArray(GateRef glue,GateRef typedArray,GateRef array)212 GateRef TypedArrayStubBuilder::FastCopyElementToArray(GateRef glue, GateRef typedArray, GateRef array)
213 {
214 auto env = GetEnvironment();
215 Label entryPass(env);
216 env->SubCfgEntry(&entryPass);
217 DEFVARIABLE(result, VariableType::BOOL(), True());
218 DEFVARIABLE(start, VariableType::INT32(), Int32(0));
219 Label exit(env);
220 Label isDetached(env);
221 Label notDetached(env);
222 Label slowPath(env);
223 Label begin(env);
224 Label storeValue(env);
225 Label endLoop(env);
226
227 GateRef buffer = GetViewedArrayBuffer(typedArray);
228 Branch(IsDetachedBuffer(buffer), &isDetached, ¬Detached);
229 Bind(&isDetached);
230 {
231 result = False();
232 Jump(&slowPath);
233 }
234 Bind(¬Detached);
235 {
236 GateRef arrLen = GetArrayLength(typedArray);
237 GateRef offset = GetByteOffset(typedArray);
238 GateRef hclass = LoadHClass(typedArray);
239 GateRef jsType = GetObjectType(hclass);
240
241 Jump(&begin);
242 LoopBegin(&begin);
243 {
244 Branch(Int32UnsignedLessThan(*start, arrLen), &storeValue, &exit);
245 Bind(&storeValue);
246 {
247 GateRef value = GetValueFromBuffer(buffer, *start, offset, jsType);
248 SetValueToTaggedArray(VariableType::JS_ANY(), glue, array, *start, value);
249 start = Int32Add(*start, Int32(1));
250 Jump(&endLoop);
251 }
252 Bind(&endLoop);
253 LoopEnd(&begin);
254 }
255 }
256 Bind(&slowPath);
257 {
258 CallRuntime(glue, RTSTUB_ID(FastCopyElementToArray), { typedArray, array});
259 Jump(&exit);
260 }
261 Bind(&exit);
262 auto ret = *result;
263 env->SubCfgExit();
264 return ret;
265 }
266
GetValueFromBuffer(GateRef buffer,GateRef index,GateRef offset,GateRef jsType)267 GateRef TypedArrayStubBuilder::GetValueFromBuffer(GateRef buffer, GateRef index, GateRef offset, GateRef jsType)
268 {
269 auto env = GetEnvironment();
270 Label entryPass(env);
271 env->SubCfgEntry(&entryPass);
272 DEFVARIABLE(result, VariableType::JS_ANY(), Undefined());
273 Label exit(env);
274 Label defaultLabel(env);
275 Label isInt8(env);
276 Label notInt8(env);
277 Label isInt16(env);
278 Label notInt16(env);
279
280 Label labelBuffer[3] = { Label(env), Label(env), Label(env) };
281 Label labelBuffer1[3] = { Label(env), Label(env), Label(env) };
282 Label labelBuffer2[3] = { Label(env), Label(env), Label(env) };
283 int64_t valueBuffer[3] = {
284 static_cast<int64_t>(JSType::JS_INT8_ARRAY), static_cast<int64_t>(JSType::JS_UINT8_ARRAY),
285 static_cast<int64_t>(JSType::JS_UINT8_CLAMPED_ARRAY) };
286 int64_t valueBuffer1[3] = {
287 static_cast<int64_t>(JSType::JS_INT16_ARRAY), static_cast<int64_t>(JSType::JS_UINT16_ARRAY),
288 static_cast<int64_t>(JSType::JS_INT32_ARRAY) };
289 int64_t valueBuffer2[3] = {
290 static_cast<int64_t>(JSType::JS_UINT32_ARRAY), static_cast<int64_t>(JSType::JS_FLOAT32_ARRAY),
291 static_cast<int64_t>(JSType::JS_FLOAT64_ARRAY) };
292
293 Branch(Int32LessThanOrEqual(jsType, Int32(static_cast<int32_t>(JSType::JS_UINT8_CLAMPED_ARRAY))),
294 &isInt8, ¬Int8);
295 Bind(&isInt8);
296 {
297 // 3 : this switch has 3 case
298 Switch(jsType, &defaultLabel, valueBuffer, labelBuffer, 3);
299 Bind(&labelBuffer[0]);
300 {
301 GateRef byteIndex = Int32Add(index, offset);
302 GateRef block = GetDataPointFromBuffer(buffer);
303 GateRef re = Load(VariableType::INT8(), block, byteIndex);
304 result = IntToTaggedPtr(SExtInt8ToInt32(re));
305 Jump(&exit);
306 }
307
308 Bind(&labelBuffer[1]);
309 {
310 GateRef byteIndex = Int32Add(index, offset);
311 GateRef block = GetDataPointFromBuffer(buffer);
312 GateRef re = Load(VariableType::INT8(), block, byteIndex);
313 result = IntToTaggedPtr(ZExtInt8ToInt32(re));
314 Jump(&exit);
315 }
316 // 2 : index of this buffer
317 Bind(&labelBuffer[2]);
318 {
319 GateRef byteIndex = Int32Add(index, offset);
320 GateRef block = GetDataPointFromBuffer(buffer);
321 GateRef re = Load(VariableType::INT8(), block, byteIndex);
322 result = IntToTaggedPtr(ZExtInt8ToInt32(re));
323 Jump(&exit);
324 }
325 }
326
327 Bind(¬Int8);
328 {
329 Branch(Int32LessThanOrEqual(jsType, Int32(static_cast<int32_t>(JSType::JS_INT32_ARRAY))),
330 &isInt16, ¬Int16);
331 Bind(&isInt16);
332 {
333 // 3 : this switch has 3 case
334 Switch(jsType, &defaultLabel, valueBuffer1, labelBuffer1, 3);
335 Bind(&labelBuffer1[0]);
336 {
337 GateRef byteIndex = Int32Add(Int32Mul(index, Int32(base::ElementSize::TWO)), offset);
338 GateRef block = GetDataPointFromBuffer(buffer);
339 GateRef re = Load(VariableType::INT16(), block, byteIndex);
340 result = IntToTaggedPtr(SExtInt16ToInt32(re));
341 Jump(&exit);
342 }
343
344 Bind(&labelBuffer1[1]);
345 {
346 GateRef byteIndex = Int32Add(Int32Mul(index, Int32(base::ElementSize::TWO)), offset);
347 GateRef block = GetDataPointFromBuffer(buffer);
348 GateRef re = Load(VariableType::INT16(), block, byteIndex);
349 result = IntToTaggedPtr(ZExtInt16ToInt32(re));
350 Jump(&exit);
351 }
352 // 2 : index of this buffer
353 Bind(&labelBuffer1[2]);
354 {
355 GateRef byteIndex = Int32Add(Int32Mul(index, Int32(base::ElementSize::FOUR)), offset);
356 GateRef block = GetDataPointFromBuffer(buffer);
357 GateRef re = Load(VariableType::INT32(), block, byteIndex);
358 result = IntToTaggedPtr(re);
359 Jump(&exit);
360 }
361 }
362 Bind(¬Int16);
363 {
364 // 3 : this switch has 3 case
365 Switch(jsType, &defaultLabel, valueBuffer2, labelBuffer2, 3);
366 Bind(&labelBuffer2[0]);
367 {
368 Label overflow(env);
369 Label notOverflow(env);
370 GateRef byteIndex = Int32Add(Int32Mul(index, Int32(base::ElementSize::FOUR)), offset);
371 GateRef block = GetDataPointFromBuffer(buffer);
372 GateRef re = Load(VariableType::INT32(), block, byteIndex);
373
374 auto condition = Int32UnsignedGreaterThan(re, Int32(INT32_MAX));
375 Branch(condition, &overflow, ¬Overflow);
376 Bind(&overflow);
377 {
378 result = DoubleToTaggedDoublePtr(ChangeUInt32ToFloat64(re));
379 Jump(&exit);
380 }
381 Bind(¬Overflow);
382 {
383 result = IntToTaggedPtr(re);
384 Jump(&exit);
385 }
386 }
387 Bind(&labelBuffer2[1]);
388 {
389 GateRef byteIndex = Int32Add(Int32Mul(index, Int32(base::ElementSize::FOUR)), offset);
390 GateRef block = GetDataPointFromBuffer(buffer);
391 GateRef re = Load(VariableType::INT32(), block, byteIndex);
392 result = DoubleToTaggedDoublePtr(ExtFloat32ToDouble(CastInt32ToFloat32(re)));
393 Jump(&exit);
394 }
395 // 2 : index of this buffer
396 Bind(&labelBuffer2[2]);
397 {
398 GateRef byteIndex = Int32Add(Int32Mul(index, Int32(base::ElementSize::EIGHT)), offset);
399 GateRef block = GetDataPointFromBuffer(buffer);
400 GateRef re = Load(VariableType::INT64(), block, byteIndex);
401 result = DoubleToTaggedDoublePtr(CastInt64ToFloat64(re));
402 Jump(&exit);
403 }
404 }
405 }
406
407 Bind(&defaultLabel);
408 {
409 Jump(&exit);
410 }
411 Bind(&exit);
412 auto ret = *result;
413 env->SubCfgExit();
414 return ret;
415 }
416
SubArray(GateRef glue,GateRef thisValue,GateRef relativeBegin,GateRef end,Variable * result,Label * exit,Label * slowPath)417 void TypedArrayStubBuilder::SubArray(GateRef glue, GateRef thisValue, GateRef relativeBegin, GateRef end,
418 Variable *result, Label *exit, Label *slowPath)
419 {
420 auto env = GetEnvironment();
421 Label ecmaObj(env);
422 Label typedArray(env);
423 DEFVARIABLE(beginIndex, VariableType::INT32(), Int32(0));
424 DEFVARIABLE(endIndex, VariableType::INT32(), Int32(0));
425 DEFVARIABLE(newLength, VariableType::INT32(), Int32(0));
426
427 Branch(IsEcmaObject(thisValue), &ecmaObj, slowPath);
428 Bind(&ecmaObj);
429 Branch(IsTypedArray(thisValue), &typedArray, slowPath);
430 Bind(&typedArray);
431
432 GateRef objHclass = LoadHClass(thisValue);
433 Label defaultConstructor(env);
434 Branch(HasConstructorByHClass(objHclass), slowPath, &defaultConstructor);
435 Bind(&defaultConstructor);
436 GateRef arrayLen = GetArrayLength(thisValue);
437 GateRef buffer = GetViewedArrayBuffer(thisValue);
438 Label offHeap(env);
439 Branch(BoolOr(IsJSObjectType(buffer, JSType::JS_ARRAY_BUFFER),
440 IsJSObjectType(buffer, JSType::JS_SHARED_ARRAY_BUFFER)), &offHeap, slowPath);
441 Bind(&offHeap);
442 Label notDetached(env);
443 Branch(IsDetachedBuffer(buffer), slowPath, ¬Detached);
444 Bind(¬Detached);
445
446 Label intIndex(env);
447 Branch(TaggedIsInt(relativeBegin), &intIndex, slowPath);
448 Bind(&intIndex);
449 GateRef relativeBeginInt = GetInt32OfTInt(relativeBegin);
450 beginIndex = CalArrayRelativePos(relativeBeginInt, arrayLen);
451
452 Label undefEnd(env);
453 Label defEnd(env);
454 Label calNewLength(env);
455 Label newArray(env);
456 Branch(TaggedIsUndefined(end), &undefEnd, &defEnd);
457 Bind(&undefEnd);
458 {
459 endIndex = arrayLen;
460 Jump(&calNewLength);
461 }
462 Bind(&defEnd);
463 {
464 Label intEnd(env);
465 Branch(TaggedIsInt(end), &intEnd, slowPath);
466 Bind(&intEnd);
467 {
468 GateRef endVal = GetInt32OfTInt(end);
469 endIndex = CalArrayRelativePos(endVal, arrayLen);
470 Jump(&calNewLength);
471 }
472 }
473 Bind(&calNewLength);
474 {
475 GateRef diffLen = Int32Sub(*endIndex, *beginIndex);
476 Label diffLargeZero(env);
477 Branch(Int32GreaterThan(diffLen, Int32(0)), &diffLargeZero, &newArray);
478 Bind(&diffLargeZero);
479 {
480 newLength = diffLen;
481 Jump(&newArray);
482 }
483 }
484 Bind(&newArray);
485 GateRef oldByteLength = Load(VariableType::INT32(), thisValue, IntPtr(JSTypedArray::BYTE_LENGTH_OFFSET));
486 GateRef elementSize = Int32Div(oldByteLength, arrayLen);
487 NewObjectStubBuilder newBuilder(this);
488 *result = newBuilder.NewTaggedSubArray(glue, thisValue, elementSize, *newLength, *beginIndex, objHclass, buffer);
489 Jump(exit);
490 }
491 } // namespace panda::ecmascript::kungfu
492