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