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/element_accessor.h" 17 18#include "ecmascript/js_tagged_value-inl.h" 19#include "ecmascript/tagged_array-inl.h" 20 21namespace panda::ecmascript { 22JSTaggedValue ElementAccessor::Get(JSHandle<JSObject> receiver, uint32_t idx) 23{ 24 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements()); 25 ASSERT(idx < elements->GetLength()); 26 ElementsKind kind = receiver->GetClass()->GetElementsKind(); 27 if (!elements->GetClass()->IsMutantTaggedArray()) { 28 kind = ElementsKind::GENERIC; 29 } 30 // Note: Here we can't statically decide the element type is a primitive or heap object, especially for 31 // dynamically-typed languages like JavaScript. So we simply skip the read-barrier. 32 size_t offset = JSTaggedValue::TaggedTypeSize() * idx; 33 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 34 JSTaggedType rawValue = Barriers::GetValue<JSTaggedType>(elements->GetData(), offset); 35 return GetTaggedValueWithElementsKind(rawValue, kind); 36} 37 38JSTaggedValue ElementAccessor::Get(JSObject *receiver, uint32_t idx) 39{ 40 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements()); 41 ASSERT(idx < elements->GetLength()); 42 ElementsKind kind = receiver->GetClass()->GetElementsKind(); 43 if (!elements->GetClass()->IsMutantTaggedArray()) { 44 kind = ElementsKind::GENERIC; 45 } 46 // Note: Here we can't statically decide the element type is a primitive or heap object, especially for 47 // dynamically-typed languages like JavaScript. So we simply skip the read-barrier. 48 size_t offset = JSTaggedValue::TaggedTypeSize() * idx; 49 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 50 JSTaggedType rawValue = Barriers::GetValue<JSTaggedType>(elements->GetData(), offset); 51 return GetTaggedValueWithElementsKind(rawValue, kind); 52} 53 54JSTaggedValue ElementAccessor::FastGet(JSHandle<TaggedArray> elements, uint32_t idx, ElementsKind kind) 55{ 56 ASSERT(idx < elements->GetLength()); 57 size_t offset = JSTaggedValue::TaggedTypeSize() * idx; 58 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) 59 JSTaggedType rawValue = Barriers::GetValue<JSTaggedType>(elements->GetData(), offset); 60 return GetTaggedValueWithElementsKind(rawValue, kind); 61} 62 63bool ElementAccessor::IsDictionaryMode(JSHandle<JSObject> receiver) 64{ 65 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements()); 66 return elements->GetClass()->IsDictionary(); 67} 68 69bool ElementAccessor::IsDictionaryMode(JSObject *receiver) 70{ 71 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements()); 72 return elements->GetClass()->IsDictionary(); 73} 74 75uint32_t ElementAccessor::GetElementsLength(JSHandle<JSObject> receiver) 76{ 77 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements()); 78 return elements->GetLength(); 79} 80 81uint32_t ElementAccessor::GetElementsLength(JSObject *receiver) 82{ 83 TaggedArray *elements = TaggedArray::Cast(receiver->GetElements()); 84 return elements->GetLength(); 85} 86 87JSTaggedValue ElementAccessor::GetTaggedValueWithElementsKind(JSTaggedType rawValue, ElementsKind kind) 88{ 89 JSTaggedValue convertedValue = JSTaggedValue::Hole(); 90 if (rawValue == base::SPECIAL_HOLE) { 91 return convertedValue; 92 } 93 switch (kind) { 94 case ElementsKind::INT: 95 case ElementsKind::HOLE_INT: 96 convertedValue = JSTaggedValue(static_cast<int>(rawValue)); 97 break; 98 case ElementsKind::NUMBER: 99 case ElementsKind::HOLE_NUMBER: 100 convertedValue = JSTaggedValue(base::bit_cast<double>(rawValue)); 101 break; 102 case ElementsKind::HOLE: 103 case ElementsKind::NONE: 104 case ElementsKind::TAGGED: 105 case ElementsKind::STRING: 106 case ElementsKind::HOLE_TAGGED: 107 case ElementsKind::HOLE_STRING: 108 convertedValue = JSTaggedValue(rawValue); 109 break; 110 default: 111 LOG_ECMA(FATAL) << "Trying to Get TaggedValue With Unknown ElementsKind"; 112 UNREACHABLE(); 113 break; 114 } 115 return convertedValue; 116} 117 118JSTaggedType ElementAccessor::ConvertTaggedValueWithElementsKind(JSTaggedValue rawValue, ElementsKind kind) 119{ 120 JSTaggedType convertedValue = base::SPECIAL_HOLE; 121 if (rawValue.IsHole() && Elements::IsInNumbers(kind)) { 122 return convertedValue; 123 } 124 switch (kind) { 125 case ElementsKind::INT: 126 case ElementsKind::HOLE_INT: 127 convertedValue = static_cast<JSTaggedType>(rawValue.GetInt()); 128 break; 129 case ElementsKind::NUMBER: 130 case ElementsKind::HOLE_NUMBER: 131 if (rawValue.IsInt()) { 132 int intValue = rawValue.GetInt(); 133 convertedValue = base::bit_cast<JSTaggedType>(static_cast<double>(intValue)); 134 } else { 135 convertedValue = base::bit_cast<JSTaggedType>(rawValue.GetDouble()); 136 } 137 break; 138 case ElementsKind::HOLE: 139 case ElementsKind::NONE: 140 case ElementsKind::TAGGED: 141 case ElementsKind::STRING: 142 case ElementsKind::HOLE_TAGGED: 143 case ElementsKind::HOLE_STRING: 144 convertedValue = rawValue.GetRawData(); 145 break; 146 default: 147 LOG_ECMA(FATAL) << "Trying to Convert TaggedValue With Unknown ElementsKind"; 148 UNREACHABLE(); 149 break; 150 } 151 return convertedValue; 152} 153 154void ElementAccessor::CopyJSArrayObject(const JSThread *thread, JSHandle<JSObject>srcObj, JSHandle<JSObject>dstObj, 155 uint32_t effectiveLength) 156{ 157 ASSERT(effectiveLength <= GetElementsLength(srcObj)); 158 ASSERT(effectiveLength <= GetElementsLength(dstObj)); 159 for (uint32_t i = 0; i < effectiveLength; i++) { 160 JSHandle<JSTaggedValue> value(thread, Get(srcObj, i)); 161 Set(thread, dstObj, i, value, true); 162 } 163} 164 165void ElementAccessor::CopyJSArrayToTaggedArray(const JSThread *thread, JSHandle<JSObject>srcObj, 166 JSHandle<TaggedArray>dstElements, uint32_t effectiveLength) 167{ 168 ASSERT(effectiveLength <= GetElementsLength(srcObj)); 169 ASSERT(effectiveLength <= dstElements->GetLength()); 170 for (uint32_t i = 0; i < effectiveLength; i++) { 171 JSHandle<JSTaggedValue> value(thread, Get(srcObj, i)); 172 dstElements->Set(thread, i, value); 173 } 174} 175} // namespace panda::ecmascript 176