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 23namespace panda::ecmascript::kungfu { 24template <DataViewType type> 25void 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 102template void BuiltinsDataViewStubBuilder::SetTypedValue<DataViewType::INT32>(GateRef glue, GateRef thisValue, 103 GateRef numArgs, Variable* res, Label *exit, Label *slowPath); 104template void BuiltinsDataViewStubBuilder::SetTypedValue<DataViewType::FLOAT32>(GateRef glue, GateRef thisValue, 105 GateRef numArgs, Variable* res, Label *exit, Label *slowPath); 106template void BuiltinsDataViewStubBuilder::SetTypedValue<DataViewType::FLOAT64>(GateRef glue, GateRef thisValue, 107 GateRef numArgs, Variable* res, Label *exit, Label *slowPath); 108 109void 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 144void 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 196GateRef 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