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 offset = GetByteOffset(thisValue);
73 GateRef size = GetByteLength(thisValue);
74 GateRef elementSize = GetElementSize(type);
75 BRANCH(Int32GreaterThan(Int32Add(index, elementSize), size), slowPath, &setValue);
76 Bind(&setValue);
77 {
78 GateRef bufferIndex = Int32Add(index, offset);
79 BuiltinsTypedArrayStubBuilder builder(this);
80 GateRef pointer = builder.GetDataPointFromBuffer(buffer);
81 GateRef doubleValue = TaggedGetNumber(value);
82 if constexpr (type == DataViewType::INT32 || type == DataViewType::UINT32) {
83 SetValueInBufferForInt32(glue, pointer, bufferIndex,
84 DoubleToInt(glue, doubleValue), *isLittleEndian);
85 } else if constexpr (type == DataViewType::FLOAT32) {
86 GateRef flaotValue = TruncDoubleToFloat32(doubleValue);
87 SetValueInBufferForInt32(glue, pointer, bufferIndex,
88 CastFloat32ToInt32(flaotValue), *isLittleEndian);
89 } else if constexpr (type == DataViewType::FLOAT64) {
90 GateRef int64Value = CastDoubleToInt64(doubleValue);
91 SetValueInBufferForInt64(glue, pointer, bufferIndex,
92 int64Value, *isLittleEndian);
93 }
94 Jump(exit);
95 }
96 }
97 }
98 }
99 }
100 }
101
102 template void BuiltinsDataViewStubBuilder::SetTypedValue<DataViewType::INT32>(GateRef glue, GateRef thisValue,
103 GateRef numArgs, Variable* res, Label *exit, Label *slowPath);
104 template void BuiltinsDataViewStubBuilder::SetTypedValue<DataViewType::FLOAT32>(GateRef glue, GateRef thisValue,
105 GateRef numArgs, Variable* res, Label *exit, Label *slowPath);
106 template void BuiltinsDataViewStubBuilder::SetTypedValue<DataViewType::FLOAT64>(GateRef glue, GateRef thisValue,
107 GateRef numArgs, Variable* res, Label *exit, Label *slowPath);
108
SetValueInBufferForInt32(GateRef glue,GateRef pointer,GateRef offset,GateRef value,GateRef littleEndianHandle)109 void BuiltinsDataViewStubBuilder::SetValueInBufferForInt32(GateRef glue, GateRef pointer, GateRef offset,
110 GateRef value, GateRef littleEndianHandle)
111 {
112 auto env = GetEnvironment();
113 Label subentry(env);
114 env->SubCfgEntry(&subentry);
115 Label exit(env);
116 Label littleEnd(env);
117 Label notLittleEnd(env);
118 GateRef b0 = Int32And(value, Int32(0xFF));
119 GateRef b1 = Int32And(Int32LSR(value, Int32(builtins::BITS_EIGHT)), Int32(0xFF));
120 GateRef b2 = Int32And(Int32LSR(value, Int32(2 * builtins::BITS_EIGHT)), Int32(0xFF));
121 GateRef b3 = Int32LSR(value, Int32(builtins::BITS_TWENTY_FOUR));
122
123 BRANCH(TaggedIsTrue(littleEndianHandle), &littleEnd, ¬LittleEnd);
124 Bind(&littleEnd);
125 {
126 Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b0));
127 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b1));
128 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b2));
129 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b3));
130 Jump(&exit);
131 }
132 Bind(¬LittleEnd);
133 {
134 Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b3));
135 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b2));
136 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b1));
137 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b0));
138 Jump(&exit);
139 }
140 Bind(&exit);
141 env->SubCfgExit();
142 }
143
SetValueInBufferForInt64(GateRef glue,GateRef pointer,GateRef offset,GateRef value,GateRef littleEndianHandle)144 void BuiltinsDataViewStubBuilder::SetValueInBufferForInt64(GateRef glue, GateRef pointer, GateRef offset,
145 GateRef value, GateRef littleEndianHandle)
146 {
147 auto env = GetEnvironment();
148 Label subentry(env);
149 env->SubCfgEntry(&subentry);
150 Label exit(env);
151 Label littleEnd(env);
152 Label notLittleEnd(env);
153 GateRef lowerInt32 = TruncInt64ToInt32(Int64And(value, Int64(0xFFFFFFFF))); // NOLINT
154 GateRef highInt32 = TruncInt64ToInt32(Int64LSR(Int64And(value, Int64(0xFFFFFFFF00000000)), Int64(32))); // NOLINT
155
156 GateRef b0 = Int32And(lowerInt32, Int32(builtins::BITS_MASK_FF));
157 GateRef b1 = Int32And(Int32LSR(lowerInt32, Int32(builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF));
158 // 2: 2 * 8 bits
159 GateRef b2 = Int32And(Int32LSR(lowerInt32, Int32(2 * builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF));
160 GateRef b3 = Int32LSR(lowerInt32, Int32(builtins::BITS_TWENTY_FOUR));
161 GateRef b4 = Int32And(highInt32, Int32(builtins::BITS_MASK_FF));
162 GateRef b5 = Int32And(Int32LSR(highInt32, Int32(builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF));
163 // 2: 2 * 8 bits
164 GateRef b6 = Int32And(Int32LSR(highInt32, Int32(2 * builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF));
165 GateRef b7 = Int32LSR(highInt32, Int32(builtins::BITS_TWENTY_FOUR));
166
167 BRANCH(TaggedIsTrue(littleEndianHandle), &littleEnd, ¬LittleEnd);
168 Bind(&littleEnd);
169 {
170 Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b0));
171 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b1));
172 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b2));
173 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b3));
174 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FOUR)), TruncInt32ToInt8(b4));
175 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FIVE)), TruncInt32ToInt8(b5));
176 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SIX)), TruncInt32ToInt8(b6));
177 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SEVEN)), TruncInt32ToInt8(b7));
178 Jump(&exit);
179 }
180 Bind(¬LittleEnd);
181 {
182 Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b7));
183 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b6));
184 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b5));
185 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b4));
186 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FOUR)), TruncInt32ToInt8(b3));
187 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FIVE)), TruncInt32ToInt8(b2));
188 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SIX)), TruncInt32ToInt8(b1));
189 Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SEVEN)), TruncInt32ToInt8(b0));
190 Jump(&exit);
191 }
192 Bind(&exit);
193 env->SubCfgExit();
194 }
195
GetElementSize(DataViewType type)196 GateRef BuiltinsDataViewStubBuilder::GetElementSize(DataViewType type)
197 {
198 GateRef size;
199 switch (type) {
200 case DataViewType::INT8:
201 case DataViewType::UINT8:
202 case DataViewType::UINT8_CLAMPED:
203 size = Int32(1);
204 break;
205 case DataViewType::INT16:
206 case DataViewType::UINT16:
207 size = Int32(2); // 2 means the length
208 break;
209 case DataViewType::INT32:
210 case DataViewType::UINT32:
211 case DataViewType::FLOAT32:
212 size = Int32(4); // 4 means the length
213 break;
214 case DataViewType::FLOAT64:
215 case DataViewType::BIGINT64:
216 case DataViewType::BIGUINT64:
217 size = Int32(8); // 8 means the length
218 break;
219 default:
220 LOG_ECMA(FATAL) << "this branch is unreachable";
221 UNREACHABLE();
222 }
223 return size;
224 }
225 } // namespace panda::ecmascript::kungfu
226