1 /* 2 * Copyright (c) 2023-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 #ifndef ECMASCRIPT_BASE_FAST_JSON_STRINGIFY_H 17 #define ECMASCRIPT_BASE_FAST_JSON_STRINGIFY_H 18 19 #include "ecmascript/ecma_context.h" 20 #include "ecmascript/js_tagged_value.h" 21 #include "ecmascript/js_handle.h" 22 #include "ecmascript/object_factory.h" 23 #include "ecmascript/global_env.h" 24 #include "ecmascript/mem/c_containers.h" 25 26 namespace panda::ecmascript::base { 27 class FastJsonStringifier { 28 public: 29 static constexpr int32_t INVALID_INDEX = -1; 30 static constexpr int32_t JSON_CACHE_MASK = 62; 31 static constexpr int32_t JSON_CACHE_SIZE = 64; 32 static constexpr int32_t CACHE_MINIMUN_SIZIE = 5; 33 FastJsonStringifier() = default; 34 FastJsonStringifier(JSThread * thread)35 explicit FastJsonStringifier(JSThread *thread) : thread_(thread) {} 36 37 ~FastJsonStringifier() = default; 38 NO_COPY_SEMANTIC(FastJsonStringifier); 39 NO_MOVE_SEMANTIC(FastJsonStringifier); 40 41 JSHandle<JSTaggedValue> Stringify(const JSHandle<JSTaggedValue> &value); 42 43 private: 44 JSTaggedValue SerializeJSONProperty(const JSHandle<JSTaggedValue> &value); 45 JSTaggedValue GetSerializeValue(const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value); 46 CString SerializeObjectKey(const JSHandle<JSTaggedValue> &key, bool hasContent); 47 48 bool SerializeJSONObject(const JSHandle<JSTaggedValue> &value); 49 50 bool SerializeJSArray(const JSHandle<JSTaggedValue> &value); 51 bool SerializeJSProxy(const JSHandle<JSTaggedValue> &object); 52 53 void SerializePrimitiveRef(const JSHandle<JSTaggedValue> &primitiveRef); 54 55 bool PushValue(const JSHandle<JSTaggedValue> &value); 56 57 void PopValue(); 58 59 bool AppendJsonString(bool hasContent, CVector<std::pair<CString, int>> &strCache, int index); 60 bool FastAppendJsonString(bool hasContent, CString &key); 61 bool TryCacheSerializeElements(const JSHandle<JSObject> &obj, bool hasContent, 62 CVector<std::pair<CString, int>> &strCache); 63 bool SerializeElementsWithCache(const JSHandle<JSObject> &obj, bool hasContent, 64 CVector<std::pair<CString, int>> &strCache, uint32_t &cacheIndex, 65 uint32_t elementSize); 66 bool TryCacheSerializeKeys(const JSHandle<JSObject> &obj, bool hasContent, 67 CVector<std::pair<CString, int>> &strCache); 68 bool TryCacheSerializeKeysFromPropertiesArray(const JSHandle<JSObject> &obj, bool hasContent, 69 CVector<std::pair<CString, int>> &strCache); 70 bool TryCacheSerializeKeysFromEnumCache(const JSHandle<JSObject> &obj, bool hasContent, 71 CVector<std::pair<CString, int>> &strCache); 72 bool TryCacheSerializeKeysFromGlobalObject(const JSHandle<JSObject> &obj, bool hasContent, 73 CVector<std::pair<CString, int>> &strCache); 74 bool TryCacheSerializeKeysFromNameDictionary(const JSHandle<JSObject> &obj, bool hasContent, 75 CVector<std::pair<CString, int>> &strCache); 76 bool SerializeKeysWithCache(const JSHandle<JSObject> &obj, bool hasContent, 77 CVector<std::pair<CString, int>> &strCache, uint32_t &cacheIndex); 78 bool AppendJsonString(bool hasContent); 79 bool DefaultSerializeKeys(const JSHandle<JSObject> &obj, bool hasContent); 80 bool SerializeKeysFromCache(const JSHandle<JSObject> &obj, JSTaggedValue enumCache, 81 const JSHandle<TaggedArray> &propertiesArr, bool hasContent); 82 bool SerializeKeysFromLayout(const JSHandle<JSObject> &obj, const JSHandle<JSHClass> &jsHclass, 83 const JSHandle<TaggedArray> &propertiesArr, bool hasContent); 84 bool SerializeKeysFromGlobalDictionary(const JSHandle<JSObject> &obj, 85 const JSHandle<TaggedArray> &propertiesArr, 86 bool hasContent); 87 bool SerializeKeysFromNameDictionary(const JSHandle<JSObject> &obj, 88 const JSHandle<TaggedArray> &propertiesArr, 89 bool hasContent); 90 bool SerializeKeyValue(const JSHandle<JSObject> &obj, JSTaggedValue key, 91 const JSHandle<TaggedArray> &propertiesArr, bool hasContent); 92 bool DefaultSerializeElements(const JSHandle<JSObject> &obj, bool hasContent); 93 bool DefaultSerializeObject(const JSTaggedValue &object, uint32_t numOfKeys, uint32_t numOfElements); 94 EraseKeyString(CString & keyStr,bool hasContent)95 inline void EraseKeyString(CString &keyStr, bool hasContent) 96 { 97 size_t keyLength = keyStr.length() + (hasContent ? 1 : 0) + 1; 98 result_.erase(result_.end() - keyLength, result_.end()); 99 } 100 FastSerializeObjectKey(CString & key,bool hasContent)101 inline void FastSerializeObjectKey(CString &key, bool hasContent) 102 { 103 if (hasContent) { 104 result_ += ","; 105 } 106 107 result_ += key; 108 result_ += ":"; 109 } 110 FindCache(JSHClass * hclass,size_t numOfKeys)111 inline int32_t FindCache(JSHClass *hclass, size_t numOfKeys) 112 { 113 size_t index = GetHash(hclass, numOfKeys); 114 JSTaggedValue cacheHclass = hclassCache_->Get(index); 115 if (cacheHclass != JSTaggedValue::Hole()) { 116 if (JSHClass::Cast(cacheHclass.GetTaggedObject()) == hclass) { 117 return index; 118 } else { 119 cacheHclass = hclassCache_->Get(++index); 120 if (JSHClass::Cast(cacheHclass.GetTaggedObject()) == hclass) { 121 return index; 122 } else { 123 return INVALID_INDEX; 124 } 125 } 126 } 127 return INVALID_INDEX; 128 } 129 SetCache(JSHClass * hclass,size_t numOfKeys,CVector<std::pair<CString,int>> & value)130 inline void SetCache(JSHClass *hclass, size_t numOfKeys, CVector<std::pair<CString, int>> &value) 131 { 132 size_t index = GetHash(hclass, numOfKeys); 133 JSTaggedValue cacheHclass = hclassCache_->Get(index); 134 if (cacheHclass != JSTaggedValue::Hole()) { 135 cacheHclass = hclassCache_->Get(++index); 136 if (cacheHclass != JSTaggedValue::Hole()) { 137 --index; 138 } 139 } 140 hclassCache_->Set(thread_, index, JSTaggedValue(hclass)); 141 thread_->GetCurrentEcmaContext()->SetJsonStringifyCache(index, value); 142 } 143 GetHash(JSHClass * hclass,size_t numOfKeys)144 inline size_t GetHash(JSHClass *hclass, size_t numOfKeys) 145 { 146 uintptr_t ptr = reinterpret_cast<uintptr_t>(hclass); 147 size_t hash = (ptr + numOfKeys) & JSON_CACHE_MASK; 148 return hash; 149 } 150 151 CString result_; 152 JSThread *thread_ {nullptr}; 153 ObjectFactory *factory_ {nullptr}; 154 CVector<JSHandle<JSTaggedValue>> stack_; 155 JSMutableHandle<JSTaggedValue> handleKey_ {}; 156 JSMutableHandle<JSTaggedValue> handleValue_ {}; 157 bool cacheable_ {true}; 158 JSHandle<TaggedArray> hclassCache_ {}; 159 }; 160 } // namespace panda::ecmascript::basekey 161 #endif // ECMASCRIPT_BASE_FAST_JSON_STRINGIFY_H 162