• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &notByteArray);
34     Bind(&isByteArray);
35     {
36         Jump(&exit);
37     }
38     Bind(&notByteArray);
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, &notByteArray);
65     Bind(&isByteArray);
66     {
67         result = PtrAdd(*result, IntPtr(ByteArray::DATA_OFFSET));
68         Jump(&exit);
69     }
70     Bind(&notByteArray);
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, &notDetached);
120     Bind(&notDetached);
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, &notDetached);
155     Bind(&notDetached);
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, &notDetached);
185     Bind(&isDetached);
186     {
187         Jump(&slowPath);
188     }
189     Bind(&notDetached);
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, &notDetached);
229     Bind(&isDetached);
230     {
231         result = False();
232         Jump(&slowPath);
233     }
234     Bind(&notDetached);
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, &notInt8);
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(&notInt8);
328     {
329         Branch(Int32LessThanOrEqual(jsType, Int32(static_cast<int32_t>(JSType::JS_INT32_ARRAY))),
330             &isInt16, &notInt16);
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(&notInt16);
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, &notOverflow);
376                 Bind(&overflow);
377                 {
378                     result = DoubleToTaggedDoublePtr(ChangeUInt32ToFloat64(re));
379                     Jump(&exit);
380                 }
381                 Bind(&notOverflow);
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, &notDetached);
444     Bind(&notDetached);
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