• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #include "ecmascript/ecma_string_table.h"
17 
18 #include "ecmascript/ecma_string-inl.h"
19 #include "ecmascript/ecma_vm.h"
20 #include "ecmascript/js_thread.h"
21 #include "ecmascript/mem/c_string.h"
22 #include "ecmascript/object_factory.h"
23 
24 namespace panda::ecmascript {
EcmaStringTable(const EcmaVM * vm)25 EcmaStringTable::EcmaStringTable(const EcmaVM *vm) : vm_(vm) {}
26 
GetString(const JSHandle<EcmaString> & firstString,const JSHandle<EcmaString> & secondString) const27 EcmaString *EcmaStringTable::GetString(const JSHandle<EcmaString> &firstString,
28                                        const JSHandle<EcmaString> &secondString) const
29 {
30     uint32_t hashCode = EcmaStringAccessor(firstString).GetHashcode();
31     hashCode = EcmaStringAccessor(secondString).ComputeHashcode(hashCode);
32     auto range = table_.equal_range(hashCode);
33     auto item = range.first;
34     for (; item != range.second; ++item) {
35         auto foundString = item->second;
36         if (EcmaStringAccessor(foundString).EqualToSplicedString(*firstString, *secondString)) {
37             return foundString;
38         }
39     }
40     return nullptr;
41 }
42 
GetString(const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress) const43 EcmaString *EcmaStringTable::GetString(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress) const
44 {
45     uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf8(utf8Data, utf8Len, canBeCompress);
46     auto range = table_.equal_range(hashCode);
47     auto item = range.first;
48     for (; item != range.second; ++item) {
49         auto foundString = item->second;
50         if (EcmaStringAccessor::StringsAreEqualUtf8(foundString, utf8Data, utf8Len, canBeCompress)) {
51             return foundString;
52         }
53     }
54     return nullptr;
55 }
56 
GetString(const uint16_t * utf16Data,uint32_t utf16Len) const57 EcmaString *EcmaStringTable::GetString(const uint16_t *utf16Data, uint32_t utf16Len) const
58 {
59     uint32_t hashCode = EcmaStringAccessor::ComputeHashcodeUtf16(const_cast<uint16_t *>(utf16Data), utf16Len);
60     auto range = table_.equal_range(hashCode);
61     auto item = range.first;
62     for (; item != range.second; ++item) {
63         auto foundString = item->second;
64         if (EcmaStringAccessor::StringsAreEqualUtf16(foundString, utf16Data, utf16Len)) {
65             return foundString;
66         }
67     }
68     return nullptr;
69 }
70 
GetString(EcmaString * string) const71 EcmaString *EcmaStringTable::GetString(EcmaString *string) const
72 {
73     auto hashcode = EcmaStringAccessor(string).GetHashcode();
74     auto range = table_.equal_range(hashcode);
75     auto item = range.first;
76     for (; item != range.second; ++item) {
77         auto foundString = item->second;
78         if (EcmaStringAccessor::StringsAreEqual(foundString, string)) {
79             return foundString;
80         }
81     }
82     return nullptr;
83 }
84 
InternString(EcmaString * string)85 void EcmaStringTable::InternString(EcmaString *string)
86 {
87     if (EcmaStringAccessor(string).IsInternString()) {
88         return;
89     }
90     table_.emplace(EcmaStringAccessor(string).GetHashcode(), string);
91     EcmaStringAccessor(string).SetInternString();
92 }
93 
InternEmptyString(EcmaString * emptyStr)94 void EcmaStringTable::InternEmptyString(EcmaString *emptyStr)
95 {
96     InternString(emptyStr);
97 }
98 
GetOrInternString(const JSHandle<EcmaString> & firstString,const JSHandle<EcmaString> & secondString)99 EcmaString *EcmaStringTable::GetOrInternString(const JSHandle<EcmaString> &firstString,
100                                                const JSHandle<EcmaString> &secondString)
101 {
102     EcmaString *concatString = GetString(firstString, secondString);
103     if (concatString != nullptr) {
104         return concatString;
105     }
106     concatString = EcmaStringAccessor::Concat(vm_, firstString, secondString);
107 
108     InternString(concatString);
109     return concatString;
110 }
111 
GetOrInternString(const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress)112 EcmaString *EcmaStringTable::GetOrInternString(const uint8_t *utf8Data, uint32_t utf8Len, bool canBeCompress)
113 {
114     EcmaString *result = GetString(utf8Data, utf8Len, canBeCompress);
115     if (result != nullptr) {
116         return result;
117     }
118 
119     result = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress);
120     InternString(result);
121     return result;
122 }
123 
124 /*
125     This function is used to create global constant strings from non-movable sapce only.
126     It only inserts string into string-table and provides no string-table validity check.
127 */
CreateAndInternStringNonMovable(const uint8_t * utf8Data,uint32_t utf8Len)128 EcmaString *EcmaStringTable::CreateAndInternStringNonMovable(const uint8_t *utf8Data, uint32_t utf8Len)
129 {
130     EcmaString *result = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, true, MemSpaceType::NON_MOVABLE);
131     InternString(result);
132     return result;
133 }
134 
GetOrInternString(const uint16_t * utf16Data,uint32_t utf16Len,bool canBeCompress)135 EcmaString *EcmaStringTable::GetOrInternString(const uint16_t *utf16Data, uint32_t utf16Len, bool canBeCompress)
136 {
137     EcmaString *result = GetString(utf16Data, utf16Len);
138     if (result != nullptr) {
139         return result;
140     }
141 
142     result = EcmaStringAccessor::CreateFromUtf16(vm_, utf16Data, utf16Len, canBeCompress);
143     InternString(result);
144     return result;
145 }
146 
GetOrInternString(EcmaString * string)147 EcmaString *EcmaStringTable::GetOrInternString(EcmaString *string)
148 {
149     if (EcmaStringAccessor(string).IsInternString()) {
150         return string;
151     }
152 
153     EcmaString *result = GetString(string);
154     if (result != nullptr) {
155         return result;
156     }
157     InternString(string);
158     return string;
159 }
160 
GetOrInternStringWithSpaceType(const uint8_t * utf8Data,uint32_t utf8Len,bool canBeCompress,MemSpaceType type)161 EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(const uint8_t *utf8Data, uint32_t utf8Len,
162                                                             bool canBeCompress, MemSpaceType type)
163 {
164     EcmaString *result = GetString(utf8Data, utf8Len, canBeCompress);
165     if (result != nullptr) {
166         return result;
167     }
168 
169     result = EcmaStringAccessor::CreateFromUtf8(vm_, utf8Data, utf8Len, canBeCompress, type);
170     InternString(result);
171     return result;
172 }
173 
GetOrInternStringWithSpaceType(const uint16_t * utf16Data,uint32_t utf16Len,bool canBeCompress,MemSpaceType type)174 EcmaString *EcmaStringTable::GetOrInternStringWithSpaceType(const uint16_t *utf16Data, uint32_t utf16Len,
175                                                             bool canBeCompress, MemSpaceType type)
176 {
177     EcmaString *result = GetString(utf16Data, utf16Len);
178     if (result != nullptr) {
179         return result;
180     }
181 
182     result = EcmaStringAccessor::CreateFromUtf16(vm_, utf16Data, utf16Len, canBeCompress, type);
183     InternString(result);
184     return result;
185 }
186 
SweepWeakReference(const WeakRootVisitor & visitor)187 void EcmaStringTable::SweepWeakReference(const WeakRootVisitor &visitor)
188 {
189     for (auto it = table_.begin(); it != table_.end();) {
190         auto *object = it->second;
191         auto fwd = visitor(object);
192         if (fwd == nullptr) {
193             LOG_ECMA(VERBOSE) << "StringTable: delete string " << std::hex << object
194                            << ", val = " << ConvertToString(object);
195             table_.erase(it++);
196         } else if (fwd != object) {
197             it->second = static_cast<EcmaString *>(fwd);
198             ++it;
199             LOG_ECMA(VERBOSE) << "StringTable: forward " << std::hex << object << " -> " << fwd;
200         } else {
201             ++it;
202         }
203     }
204 }
205 
CheckStringTableValidity()206 bool EcmaStringTable::CheckStringTableValidity()
207 {
208     for (auto itemOuter = table_.begin(); itemOuter != table_.end(); ++itemOuter) {
209         auto outerString = itemOuter->second;
210         int counter = 0;
211         auto hashcode = EcmaStringAccessor(outerString).GetHashcode();
212         auto range = table_.equal_range(hashcode);
213         auto it = range.first;
214         for (; it != range.second; ++it) {
215             auto foundString = it->second;
216             if (EcmaStringAccessor::StringsAreEqual(foundString, outerString)) {
217                 ++counter;
218             }
219         }
220         if (counter > 1) {
221             return false;
222         }
223     }
224     return true;
225 }
226 }  // namespace panda::ecmascript
227