1 /*
2 * Copyright (c) 2024 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/builtins/builtins_dataview_stub_builder.h"
17
18 #include "ecmascript/builtins/builtins_arraybuffer.h"
19 #include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h"
20
21 namespace panda::ecmascript::kungfu {
22 template <DataViewType type>
SetTypedValue(GateRef glue,GateRef thisValue,GateRef numArgs,Variable * res,Label * exit,Label * slowPath)23 void BuiltinsDataViewStubBuilder::SetTypedValue(GateRef glue, GateRef thisValue,
24 GateRef numArgs, [[maybe_unused]] Variable* res, Label *exit, Label *slowPath)
25 {
26 auto env = GetEnvironment();
27 Label thisIsHeapObject(env);
28 Label thisIsDataView(env);
29 Label indexIsInt(env);
30 BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObject, slowPath);
31 Bind(&thisIsHeapObject);
32 BRANCH(IsDataView(glue, thisValue), &thisIsDataView, slowPath);
33 Bind(&thisIsDataView);
34 GateRef indexTagged = GetCallArg0(numArgs);
35 GateRef value = GetCallArg1(numArgs);
36 BRANCH(TaggedIsInt(indexTagged), &indexIsInt, slowPath);
37 Bind(&indexIsInt);
38 {
39 DEFVARIABLE(isLittleEndian, VariableType::JS_ANY(), TaggedFalse());
40 Label indexIsValid(env);
41 Label valueIsValid(env);
42 Label checkOffset(env);
43 Label getArrayBuffer(env);
44 Label setValue(env);
45 Label toBool(env);
46 GateRef index = GetInt32OfTInt(indexTagged);
47 BRANCH(Int32LessThan(index, Int32(0)), slowPath, &indexIsValid);
48 Bind(&indexIsValid);
49 {
50 BRANCH(TaggedIsNumber(value), &valueIsValid, slowPath);
51 Bind(&valueIsValid);
52 GateRef littleEndianHandle; // need to init
53 if constexpr (type == DataViewType::UINT8 || type == DataViewType::INT8) {
54 littleEndianHandle = TaggedTrue();
55 } else {
56 littleEndianHandle = GetCallArg2(numArgs);
57 }
58 BRANCH(TaggedIsUndefined(littleEndianHandle), &getArrayBuffer, &toBool);
59 Bind(&toBool);
60 {
61 isLittleEndian = FastToBoolean(glue, littleEndianHandle, 1);
62 Jump(&getArrayBuffer);
63 }
64 Bind(&getArrayBuffer);
65 {
66 GateRef buffer = GetViewedArrayBuffer(glue, thisValue);
67 BRANCH(IsDetachedBuffer(glue, buffer), slowPath, &checkOffset);
68 Bind(&checkOffset);
69 {
70 GateRef size = ZExtInt32ToInt64(GetByteLength(thisValue));
71 GateRef elementSize = GetElementSize(type);
72 GateRef indexInt64 = ZExtInt32ToInt64(index);
73 BRANCH(Int64UnsignedGreaterThan(Int64Add(indexInt64, elementSize), size), slowPath, &setValue);
74 Bind(&setValue);
75 {
76 GateRef offset = ZExtInt32ToInt64(GetByteOffset(thisValue));
77 GateRef bufferIndex = TruncInt64ToInt32(Int64Add(indexInt64, offset));
78 BuiltinsTypedArrayStubBuilder builder(this, GetCurrentGlobalEnv());
79 GateRef pointer = builder.GetDataPointFromBuffer(glue, buffer);
80 GateRef doubleValue = TaggedGetNumber(value);
81 if constexpr (type == DataViewType::INT32 || type == DataViewType::UINT32) {
82 SetValueInBufferForInt32(glue, pointer, bufferIndex,
83 DoubleToInt(glue, doubleValue), *isLittleEndian);
84 } else if constexpr (type == DataViewType::FLOAT32) {
85 GateRef flaotValue = TruncDoubleToFloat32(doubleValue);
86 SetValueInBufferForInt32(glue, pointer, bufferIndex,
87 CastFloat32ToInt32(flaotValue), *isLittleEndian);
88 } else if constexpr (type == DataViewType::FLOAT64) {
89 GateRef int64Value = CastDoubleToInt64(doubleValue);
90 SetValueInBufferForInt64(glue, pointer, bufferIndex,
91 int64Value, *isLittleEndian);
92 }
93 Jump(exit);
94 }
95 }
96 }
97 }
98 }
99 }
100
101 template void BuiltinsDataViewStubBuilder::SetTypedValue<DataViewType::INT32>(GateRef glue, GateRef thisValue,
102 GateRef numArgs, Variable* res, Label *exit, Label *slowPath);
103 template void BuiltinsDataViewStubBuilder::SetTypedValue<DataViewType::FLOAT32>(GateRef glue, GateRef thisValue,
104 GateRef numArgs, Variable* res, Label *exit, Label *slowPath);
105 template void BuiltinsDataViewStubBuilder::SetTypedValue<DataViewType::FLOAT64>(GateRef glue, GateRef thisValue,
106 GateRef numArgs, Variable* res, Label *exit, Label *slowPath);
107
SetValueInBufferForInt32(GateRef glue,GateRef pointer,GateRef offset,GateRef value,GateRef littleEndianHandle)108 void BuiltinsDataViewStubBuilder::SetValueInBufferForInt32(GateRef glue, GateRef pointer, GateRef offset,
109 GateRef value, GateRef littleEndianHandle)
110 {
111 auto env = GetEnvironment();
112 Label subentry(env);
113 env->SubCfgEntry(&subentry);
114 Label exit(env);
115 Label littleEnd(env);
116 Label notLittleEnd(env);
117 GateRef b0 = Int32And(value, Int32(0xFF));
118 GateRef b1 = Int32And(Int32LSR(value, Int32(builtins::BITS_EIGHT)), Int32(0xFF));
119 GateRef b2 = Int32And(Int32LSR(value, Int32(2 * builtins::BITS_EIGHT)), Int32(0xFF));
120 GateRef b3 = Int32LSR(value, Int32(builtins::BITS_TWENTY_FOUR));
121
122 BRANCH(TaggedIsTrue(littleEndianHandle), &littleEnd, ¬LittleEnd);
123 Bind(&littleEnd);
124 {
125 Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b0));
126 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b1));
127 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b2));
128 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b3));
129 Jump(&exit);
130 }
131 Bind(¬LittleEnd);
132 {
133 Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b3));
134 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b2));
135 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b1));
136 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b0));
137 Jump(&exit);
138 }
139 Bind(&exit);
140 env->SubCfgExit();
141 }
142
SetValueInBufferForInt64(GateRef glue,GateRef pointer,GateRef offset,GateRef value,GateRef littleEndianHandle)143 void BuiltinsDataViewStubBuilder::SetValueInBufferForInt64(GateRef glue, GateRef pointer, GateRef offset,
144 GateRef value, GateRef littleEndianHandle)
145 {
146 auto env = GetEnvironment();
147 Label subentry(env);
148 env->SubCfgEntry(&subentry);
149 Label exit(env);
150 Label littleEnd(env);
151 Label notLittleEnd(env);
152 GateRef lowerInt32 = TruncInt64ToInt32(Int64And(value, Int64(0xFFFFFFFF))); // NOLINT
153 GateRef highInt32 = TruncInt64ToInt32(Int64LSR(Int64And(value, Int64(0xFFFFFFFF00000000)), Int64(32))); // NOLINT
154
155 GateRef b0 = Int32And(lowerInt32, Int32(builtins::BITS_MASK_FF));
156 GateRef b1 = Int32And(Int32LSR(lowerInt32, Int32(builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF));
157 // 2: 2 * 8 bits
158 GateRef b2 = Int32And(Int32LSR(lowerInt32, Int32(2 * builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF));
159 GateRef b3 = Int32LSR(lowerInt32, Int32(builtins::BITS_TWENTY_FOUR));
160 GateRef b4 = Int32And(highInt32, Int32(builtins::BITS_MASK_FF));
161 GateRef b5 = Int32And(Int32LSR(highInt32, Int32(builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF));
162 // 2: 2 * 8 bits
163 GateRef b6 = Int32And(Int32LSR(highInt32, Int32(2 * builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF));
164 GateRef b7 = Int32LSR(highInt32, Int32(builtins::BITS_TWENTY_FOUR));
165
166 BRANCH(TaggedIsTrue(littleEndianHandle), &littleEnd, ¬LittleEnd);
167 Bind(&littleEnd);
168 {
169 Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b0));
170 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b1));
171 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b2));
172 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b3));
173 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FOUR)), TruncInt32ToInt8(b4));
174 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FIVE)), TruncInt32ToInt8(b5));
175 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SIX)), TruncInt32ToInt8(b6));
176 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SEVEN)), TruncInt32ToInt8(b7));
177 Jump(&exit);
178 }
179 Bind(¬LittleEnd);
180 {
181 Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b7));
182 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b6));
183 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b5));
184 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b4));
185 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FOUR)), TruncInt32ToInt8(b3));
186 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FIVE)), TruncInt32ToInt8(b2));
187 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SIX)), TruncInt32ToInt8(b1));
188 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SEVEN)), TruncInt32ToInt8(b0));
189 Jump(&exit);
190 }
191 Bind(&exit);
192 env->SubCfgExit();
193 }
194
GetElementSize(DataViewType type)195 GateRef BuiltinsDataViewStubBuilder::GetElementSize(DataViewType type)
196 {
197 GateRef size;
198 switch (type) {
199 case DataViewType::INT8:
200 case DataViewType::UINT8:
201 case DataViewType::UINT8_CLAMPED:
202 size = Int64(1);
203 break;
204 case DataViewType::INT16:
205 case DataViewType::UINT16:
206 size = Int64(2); // 2 means the length
207 break;
208 case DataViewType::INT32:
209 case DataViewType::UINT32:
210 case DataViewType::FLOAT32:
211 size = Int64(4); // 4 means the length
212 break;
213 case DataViewType::FLOAT64:
214 case DataViewType::BIGINT64:
215 case DataViewType::BIGUINT64:
216 size = Int64(8); // 8 means the length
217 break;
218 default:
219 LOG_ECMA(FATAL) << "this branch is unreachable";
220 UNREACHABLE();
221 }
222 return size;
223 }
224 } // namespace panda::ecmascript::kungfu
225