1 /* 2 * Copyright (c) 2021-2022 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_JSPANDAFILE_CLASS_INFO_EXTRACTOR_H 17 #define ECMASCRIPT_JSPANDAFILE_CLASS_INFO_EXTRACTOR_H 18 19 #include "ecmascript/js_tagged_value-inl.h" 20 #include "ecmascript/js_tagged_value.h" 21 #include "ecmascript/js_tagged_value_internals.h" 22 #include "ecmascript/jspandafile/method_literal.h" 23 24 namespace panda::ecmascript { 25 // ClassInfoExtractor will analyze and extract the contents from class literal to keys, properties and elements(both 26 // non-static and static), later generate the complete hclass (both prototype and constructor) based on keys. 27 // Attention: keys accessor stores the property key and properties accessor stores the property value, but elements 28 // accessor stores the key-value pair abuttally. 29 using EntityId = panda_file::File::EntityId; 30 enum class FieldType { 31 NONE = 0, 32 NUMBER = (1 << 0), 33 STRING = (1 << 1), 34 BOOLEAN = (1 << 2), 35 TS_TYPE_REF = (1 << 3), 36 }; 37 class ClassInfoExtractor : public TaggedObject { 38 public: 39 static constexpr uint8_t NON_STATIC_RESERVED_LENGTH = 1; 40 static constexpr uint8_t STATIC_RESERVED_LENGTH = 3; 41 42 static constexpr uint8_t CONSTRUCTOR_INDEX = 0; 43 static constexpr uint8_t LENGTH_INDEX = 0; 44 static constexpr uint8_t NAME_INDEX = 1; 45 static constexpr uint8_t PROTOTYPE_INDEX = 2; 46 47 struct ExtractContentsDetail { 48 uint32_t extractBegin; 49 uint32_t extractEnd; 50 uint8_t fillStartLoc; 51 MethodLiteral *methodLiteral; 52 }; 53 54 CAST_CHECK(ClassInfoExtractor, IsClassInfoExtractor); 55 56 static void BuildClassInfoExtractorFromLiteral(JSThread *thread, JSHandle<ClassInfoExtractor> &extractor, 57 const JSHandle<TaggedArray> &literal); 58 59 static JSHandle<JSHClass> CreatePrototypeHClass(JSThread *thread, 60 JSHandle<TaggedArray> &keys, 61 JSHandle<TaggedArray> &properties); 62 63 static JSHandle<JSHClass> CreateConstructorHClass(JSThread *thread, const JSHandle<JSTaggedValue> &base, 64 JSHandle<TaggedArray> &keys, 65 JSHandle<TaggedArray> &properties); 66 static JSHandle<JSHClass> CreateSendableHClass(JSThread *thread, JSHandle<TaggedArray> &keys, 67 JSHandle<TaggedArray> &properties, bool isProtoClass, 68 uint32_t extraLength = 0); 69 static void CorrectConstructorHClass(JSThread *thread, 70 JSHandle<TaggedArray> &properties, 71 JSHClass *constructorHClass); 72 73 static constexpr size_t PROTOTYPE_HCLASS_OFFSET = TaggedObjectSize(); 74 ACCESSORS(NonStaticKeys, PROTOTYPE_HCLASS_OFFSET, NON_STATIC_PROPERTIES_OFFSET) 75 ACCESSORS(NonStaticProperties, NON_STATIC_PROPERTIES_OFFSET, NON_STATIC_ELEMENTS_OFFSET) 76 ACCESSORS(NonStaticElements, NON_STATIC_ELEMENTS_OFFSET, CONSTRUCTOR_HCLASS_OFFSET) 77 ACCESSORS(StaticKeys, CONSTRUCTOR_HCLASS_OFFSET, STATIC_PROPERTIES_OFFSET) 78 ACCESSORS(StaticProperties, STATIC_PROPERTIES_OFFSET, STATIC_ELEMENTS_OFFSET) 79 ACCESSORS(StaticElements, STATIC_ELEMENTS_OFFSET, CONSTRUCTOR_METHOD_OFFSET) 80 ACCESSORS(ConstructorMethod, CONSTRUCTOR_METHOD_OFFSET, BIT_FIELD_OFFSET) 81 ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) 82 DEFINE_ALIGN_SIZE(LAST_OFFSET); 83 84 // define BitField 85 static constexpr size_t NON_STATIC_BITS = 1; 86 static constexpr size_t STATIC_BITS = 1; 87 FIRST_BIT_FIELD(BitField, NonStaticWithElements, bool, NON_STATIC_BITS) 88 NEXT_BIT_FIELD(BitField, StaticWithElements, bool, STATIC_BITS, NonStaticWithElements) 89 90 DECL_VISIT_OBJECT(PROTOTYPE_HCLASS_OFFSET, BIT_FIELD_OFFSET) 91 92 DECL_DUMP() 93 94 private: 95 static bool ExtractAndReturnWhetherWithElements(JSThread *thread, const JSHandle<TaggedArray> &literal, 96 const ExtractContentsDetail &detail, 97 JSHandle<TaggedArray> &keys, JSHandle<TaggedArray> &properties, 98 JSHandle<TaggedArray> &elements, 99 const JSPandaFile *jsPandaFile); 100 }; 101 102 enum class ClassPropertyType : uint8_t { NON_STATIC = 0, STATIC }; 103 104 class ClassHelper { 105 public: 106 static JSHandle<JSFunction> DefineClassFromExtractor(JSThread *thread, const JSHandle<JSTaggedValue> &base, 107 JSHandle<ClassInfoExtractor> &extractor, 108 const JSHandle<JSTaggedValue> &lexenv); 109 110 static JSHandle<JSFunction> DefineClassWithIHClass(JSThread *thread, 111 JSHandle<ClassInfoExtractor> &extractor, 112 const JSHandle<JSTaggedValue> &lexenv, 113 const JSHandle<JSTaggedValue> &ihclass, 114 const JSHandle<JSHClass> &constructorHClass); 115 116 static bool MatchTrackType(TrackType trackType, JSTaggedValue value); 117 private: 118 static JSHandle<NameDictionary> BuildDictionaryProperties(JSThread *thread, const JSHandle<JSObject> &object, 119 JSHandle<TaggedArray> &keys, 120 JSHandle<TaggedArray> &properties, ClassPropertyType type, 121 const JSHandle<JSTaggedValue> &lexenv); 122 123 static void HandleElementsProperties(JSThread *thread, const JSHandle<JSObject> &object, 124 JSHandle<TaggedArray> &elements); 125 }; 126 127 class SendableClassDefiner : public ClassHelper { 128 public: 129 static JSHandle<JSFunction> DefineSendableClassFromExtractor(JSThread *thread, 130 JSHandle<ClassInfoExtractor> &extractor, 131 const JSHandle<TaggedArray> &fieldTypeArray); 132 133 static void DefineSendableInstanceHClass(JSThread *thread, const JSHandle<TaggedArray> &fieldTypeArray, 134 const JSHandle<JSFunction> &ctor, const JSHandle<JSTaggedValue> &base); 135 136 static JSHandle<TaggedArray> ExtractStaticFieldTypeArray(JSThread *thread, 137 const JSHandle<TaggedArray> &fieldTypeArray); 138 139 static void FilterDuplicatedKeys(JSThread *thread, const JSHandle<TaggedArray> &keys, 140 const JSHandle<TaggedArray> &properties); 141 142 private: FromFieldType(FieldType type)143 static TrackType FromFieldType(FieldType type) 144 { 145 switch (type) { 146 case FieldType::NONE: 147 return TrackType::NONE; 148 case FieldType::NUMBER: 149 return TrackType::NUMBER; 150 case FieldType::STRING: 151 return TrackType::STRING; 152 case FieldType::BOOLEAN: 153 return TrackType::BOOLEAN; 154 case FieldType::TS_TYPE_REF: 155 return TrackType::SENDABLE; 156 default: 157 UNREACHABLE(); 158 } 159 } 160 161 static JSHandle<NameDictionary> BuildSendableDictionaryProperties(JSThread *thread, 162 const JSHandle<JSObject> &object, 163 JSHandle<TaggedArray> &keys, 164 JSHandle<TaggedArray> &properties, 165 ClassPropertyType type, 166 const JSHandle<JSFunction> &ctor); 167 168 static void UpdateAccessorFunction(JSThread *thread, const JSMutableHandle<JSTaggedValue> &value, 169 const JSHandle<JSTaggedValue> &homeObject, const JSHandle<JSFunction> &ctor); 170 171 static void AddFieldTypeToHClass(JSThread *thread, const JSHandle<TaggedArray> &fieldTypeArray, 172 const JSHandle<LayoutInfo> &layout, const JSHandle<JSHClass> &hclass); 173 174 static void AddFieldTypeToHClass(JSThread *thread, const JSHandle<TaggedArray> &fieldTypeArray, 175 const JSHandle<NameDictionary> &nameDict, const JSHandle<JSHClass> &hclass); 176 177 static void AddFieldTypeToDict(JSThread *thread, const JSHandle<TaggedArray> &fieldTypeArray, 178 JSMutableHandle<NameDictionary> &dict, 179 PropertyAttributes attributes = PropertyAttributes::Default(true, true, false)); 180 181 static bool TryUpdateExistValue(JSThread *thread, JSMutableHandle<JSTaggedValue> &existValue, 182 JSMutableHandle<JSTaggedValue> &value); 183 184 static void TryUpdateValue(JSThread *thread, JSMutableHandle<JSTaggedValue> &value); 185 186 static void UpdateValueToAccessor(JSThread *thread, JSMutableHandle<JSTaggedValue> &value, 187 JSHandle<AccessorData> &accessor); 188 }; 189 } // namespace panda::ecmascript 190 #endif // ECMASCRIPT_JSPANDAFILE_CLASS_INFO_EXTRACTOR_H 191