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