1 /* 2 * Copyright (c) 2021 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 #ifndef ECMASCRIPT_JS_HCLASS_INL_H 17 #define ECMASCRIPT_JS_HCLASS_INL_H 18 19 #include "ecmascript/js_hclass.h" 20 21 #include "ecmascript/layout_info-inl.h" 22 #include "ecmascript/byte_array.h" 23 #include "ecmascript/mem/assert_scope.h" 24 #include "ecmascript/transitions_dictionary.h" 25 26 namespace panda::ecmascript { Cast(const TaggedObject * object)27 inline JSHClass *JSHClass::Cast(const TaggedObject *object) 28 { 29 ASSERT(JSTaggedValue(object).IsJSHClass()); 30 return static_cast<JSHClass *>(const_cast<TaggedObject *>(object)); 31 } 32 AddTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key,PropertyAttributes attributes)33 void JSHClass::AddTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent, const JSHandle<JSHClass> &child, 34 const JSHandle<JSTaggedValue> &key, PropertyAttributes attributes) 35 { 36 JSTaggedValue transitions = parent->GetTransitions(); 37 if (transitions.IsUndefined()) { 38 JSTaggedValue weakChild = JSTaggedValue(child.GetTaggedValue().CreateAndGetWeakRef()); 39 parent->SetTransitions(thread, weakChild); 40 return; 41 } 42 JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined()); 43 if (transitions.IsWeak()) { 44 auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef()); 45 uint32_t last = cachedHClass->NumberOfProps() - 1; 46 LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject()); 47 auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData())); 48 auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(last)); 49 auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass); 50 dict.Update(TransitionsDictionary::Create(thread)); 51 transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue(); 52 } 53 auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(attributes.GetPropertyMetaData())); 54 dict.Update(transitions); 55 transitions = 56 TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), attr).GetTaggedValue(); 57 parent->SetTransitions(thread, transitions); 58 } 59 AddExtensionTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key)60 void JSHClass::AddExtensionTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent, 61 const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key) 62 { 63 auto attr = JSHandle<JSTaggedValue>(thread, PropertyAttributes(0).GetTaggedValue()); 64 AddProtoTransitions(thread, parent, child, key, attr); 65 } 66 AddProtoTransitions(const JSThread * thread,const JSHandle<JSHClass> & parent,const JSHandle<JSHClass> & child,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & proto)67 void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent, 68 const JSHandle<JSHClass> &child, const JSHandle<JSTaggedValue> &key, 69 const JSHandle<JSTaggedValue> &proto) 70 { 71 JSTaggedValue transitions = parent->GetTransitions(); 72 JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined()); 73 if (transitions.IsUndefined()) { 74 transitions = TransitionsDictionary::Create(thread).GetTaggedValue(); 75 } else if (transitions.IsWeak()) { 76 auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef()); 77 uint32_t last = cachedHClass->NumberOfProps() - 1; 78 LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject()); 79 auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData())); 80 auto lastKey = JSHandle<JSTaggedValue>(thread, layoutInfo->GetKey(last)); 81 auto lastHClass = JSHandle<JSTaggedValue>(thread, cachedHClass); 82 dict.Update(TransitionsDictionary::Create(thread)); 83 transitions = TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr).GetTaggedValue(); 84 } 85 86 dict.Update(transitions); 87 transitions = 88 TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), proto).GetTaggedValue(); 89 parent->SetTransitions(thread, transitions); 90 } 91 FindTransitions(const JSTaggedValue & key,const JSTaggedValue & attributes)92 inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTaggedValue &attributes) 93 { 94 DISALLOW_GARBAGE_COLLECTION; 95 JSTaggedValue transitions = GetTransitions(); 96 if (transitions.IsUndefined()) { 97 return nullptr; 98 } 99 if (transitions.IsWeak()) { 100 auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef()); 101 int last = static_cast<int>(cachedHClass->NumberOfProps()) - 1; 102 LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject()); 103 auto attr = layoutInfo->GetAttr(last).GetPropertyMetaData(); 104 auto cachedKey = layoutInfo->GetKey(last); 105 if (attr == attributes.GetInt() && key == cachedKey) { 106 return cachedHClass; 107 } 108 return nullptr; 109 } 110 111 ASSERT(transitions.IsTaggedArray()); 112 TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject()); 113 auto entry = dict->FindEntry(key, attributes); 114 if (entry == -1) { 115 return nullptr; 116 } 117 118 JSTaggedValue ret = dict->GetValue(entry); 119 if (ret.IsUndefined()) { 120 return nullptr; 121 } 122 123 return JSHClass::Cast(ret.GetTaggedWeakRef()); 124 } 125 FindProtoTransitions(const JSTaggedValue & key,const JSTaggedValue & proto)126 inline JSHClass *JSHClass::FindProtoTransitions(const JSTaggedValue &key, const JSTaggedValue &proto) 127 { 128 DISALLOW_GARBAGE_COLLECTION; 129 JSTaggedValue transitions = GetTransitions(); 130 if (transitions.IsWeak() || !transitions.IsTaggedArray()) { 131 ASSERT(transitions.IsUndefined() || transitions.IsWeak()); 132 return nullptr; 133 } 134 ASSERT(transitions.IsTaggedArray()); 135 TransitionsDictionary *dict = TransitionsDictionary::Cast(transitions.GetTaggedObject()); 136 auto entry = dict->FindEntry(key, proto); 137 if (entry == -1) { 138 return nullptr; 139 } 140 141 JSTaggedValue ret = dict->GetValue(entry); 142 if (ret.IsUndefined()) { 143 return nullptr; 144 } 145 146 return JSHClass::Cast(ret.GetTaggedWeakRef()); 147 } 148 UpdatePropertyMetaData(const JSThread * thread,const JSTaggedValue & key,const PropertyAttributes & metaData)149 inline void JSHClass::UpdatePropertyMetaData(const JSThread *thread, [[maybe_unused]] const JSTaggedValue &key, 150 const PropertyAttributes &metaData) 151 { 152 DISALLOW_GARBAGE_COLLECTION; 153 ASSERT(!GetLayout().IsNull()); 154 LayoutInfo *layoutInfo = LayoutInfo::Cast(GetLayout().GetTaggedObject()); 155 ASSERT(layoutInfo->GetLength() != 0); 156 uint32_t entry = metaData.GetOffset(); 157 158 layoutInfo->SetNormalAttr(thread, entry, metaData); 159 } 160 HasReferenceField()161 inline bool JSHClass::HasReferenceField() 162 { 163 auto type = GetObjectType(); 164 switch (type) { 165 case JSType::LINE_STRING: 166 case JSType::CONSTANT_STRING: 167 case JSType::JS_NATIVE_POINTER: 168 return false; 169 default: 170 return true; 171 } 172 } 173 SizeFromJSHClass(TaggedObject * header)174 inline size_t JSHClass::SizeFromJSHClass(TaggedObject *header) 175 { 176 // CAUTION! Never use T::Cast(header) in this function 177 // it would cause issue during GC because hclass may forward to a new addres 178 // and the casting method would still use the old address. 179 auto type = GetObjectType(); 180 size_t size = 0; 181 switch (type) { 182 case JSType::TAGGED_ARRAY: 183 case JSType::TAGGED_DICTIONARY: 184 case JSType::LEXICAL_ENV: 185 case JSType::CONSTANT_POOL: 186 case JSType::AOT_LITERAL_INFO: 187 case JSType::VTABLE: 188 case JSType::COW_TAGGED_ARRAY: 189 size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), 190 reinterpret_cast<TaggedArray *>(header)->GetLength()); 191 break; 192 case JSType::BYTE_ARRAY: 193 size = ByteArray::ComputeSize(reinterpret_cast<ByteArray *>(header)->GetByteLength(), 194 reinterpret_cast<ByteArray *>(header)->GetArrayLength()); 195 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)); 196 break; 197 case JSType::LINE_STRING: 198 size = LineEcmaString::ObjectSize(reinterpret_cast<EcmaString* >(header)); 199 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)); 200 break; 201 case JSType::CONSTANT_STRING: 202 size = ConstantString::SIZE; 203 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)); 204 break; 205 case JSType::TREE_STRING: 206 size = TreeEcmaString::SIZE; 207 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)); 208 break; 209 case JSType::MACHINE_CODE_OBJECT: 210 size = reinterpret_cast<MachineCode *>(header)->GetMachineCodeObjectSize(); 211 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)); 212 break; 213 case JSType::BIGINT: 214 size = BigInt::ComputeSize(reinterpret_cast<BigInt *>(header)->GetLength()); 215 size = AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)); 216 break; 217 default: 218 ASSERT(GetObjectSize() != 0); 219 size = GetObjectSize(); 220 break; 221 } 222 ASSERT(AlignUp(size, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) == size); 223 return size; 224 } 225 Copy(const JSThread * thread,const JSHClass * jshclass)226 inline void JSHClass::Copy(const JSThread *thread, const JSHClass *jshclass) 227 { 228 DISALLOW_GARBAGE_COLLECTION; 229 230 // copy jshclass 231 SetPrototype(thread, jshclass->GetPrototype()); 232 SetBitField(jshclass->GetBitField()); 233 SetIsAllTaggedProp(jshclass->IsAllTaggedProp()); 234 SetNumberOfProps(jshclass->NumberOfProps()); 235 } 236 FindPropertyEntry(const JSThread * thread,JSHClass * hclass,JSTaggedValue key)237 inline int JSHClass::FindPropertyEntry(const JSThread *thread, JSHClass *hclass, JSTaggedValue key) 238 { 239 DISALLOW_GARBAGE_COLLECTION; 240 LayoutInfo *layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject()); 241 uint32_t propsNumber = hclass->NumberOfProps(); 242 int entry = layout->FindElementWithCache(thread, hclass, key, propsNumber); 243 return entry; 244 } 245 } // namespace panda::ecmascript 246 247 #endif // ECMASCRIPT_JS_HCLASS_INL_H 248