• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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