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