• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 #include "ecmascript/interpreter/interpreter.h"
17 #include "ecmascript/base/json_parser.h"
18 #include "ecmascript/linked_hash_table.h"
19 #include "ecmascript/ecma_string_table.h"
20 #include "ecmascript/platform/json_platform_helper.h"
21 
22 namespace panda::ecmascript::base {
23 
24 template<typename T>
Launch(Text begin,Text end)25 JSHandle<JSTaggedValue> JsonParser<T>::Launch(Text begin, Text end)
26 {
27     // check empty
28     if (UNLIKELY(begin == end)) {
29         return JSHandle<JSTaggedValue>(thread_, [&]() -> JSTaggedValue {
30             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: Empty Text", JSTaggedValue::Exception());
31         }());
32     }
33     end_ = end - 1;
34     current_ = begin;
35     SkipEndWhiteSpace();
36     range_ = end_;
37 
38     auto vm = thread_->GetEcmaVM();
39     factory_ = vm->GetFactory();
40     env_ = *vm->GetGlobalEnv();
41 
42     // For Json, we do not support ElementsKind
43     auto index = static_cast<size_t>(GlobalEnvField::ELEMENT_HOLE_TAGGED_HCLASS_INDEX);
44     auto hclassVal = env_->GetGlobalEnvObjectByIndex(index).GetTaggedValue();
45     initialJSArrayClass_ = JSHandle<JSHClass>(thread_, hclassVal);
46     JSHandle<JSFunction> objectFunc(env_->GetObjectFunction());
47     initialJSObjectClass_ =
48         JSHandle<JSHClass>(thread_, JSFunction::GetOrCreateInitialJSHClass(thread_, objectFunc));
49 
50     JSTaggedValue result = g_isEnableCMCGC ? ParseJSONText<true>() : ParseJSONText<false>();
51     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_);
52     return JSHandle<JSTaggedValue>(thread_, result);
53 }
54 
55 template<typename T>
56 template<bool isEnableCMCGC>
ParseJSONText()57 JSTaggedValue JsonParser<T>::ParseJSONText()
58 {
59     JSHandle<JSTaggedValue> parseValue;
60     std::vector<JsonContinuation> continuationList;
61     std::vector<JSHandle<JSTaggedValue>> elementsList;
62     std::vector<JSHandle<JSTaggedValue>> propertyList;
63     continuationList.reserve(16); // 16: initial capacity
64     elementsList.reserve(16); // 16: initial capacity
65     propertyList.reserve(16); // 16: initial capacity
66     JsonContinuation continuation(ContType::RETURN, 0);
67     while (true) {
68         while (true) {
69             SkipStartWhiteSpace();
70             Tokens token = ParseToken();
71             if (current_ > range_) {
72                 THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end in JSON", JSTaggedValue::Exception());
73             }
74             switch (token) {
75                 case Tokens::OBJECT:
76                     if (EmptyObjectCheck()) {
77                         if (transformType_ == TransformType::SENDABLE) {
78                             JSHandle<JSHClass> sHclass;
79                             JSHandle<JSTaggedValue> sJsonPrototype = GetSJsonPrototype();
80                             JSHandle<LayoutInfo> sLayout = factory_->CreateSLayoutInfo(0);
81                             sHclass = factory_->NewSEcmaHClass(JSSharedObject::SIZE, 0, JSType::JS_SHARED_OBJECT,
82                                                                JSHandle<JSTaggedValue>(sJsonPrototype),
83                                                                JSHandle<JSTaggedValue>(sLayout));
84                             parseValue = JSHandle<JSTaggedValue>(factory_->NewSharedOldSpaceJSObject(sHclass));
85                         } else {
86                             parseValue = JSHandle<JSTaggedValue>(factory_->NewJSObject(initialJSObjectClass_));
87                         }
88                         GetNextNonSpaceChar();
89                         break;
90                     }
91                     continuationList.emplace_back(std::move(continuation));
92                     continuation = JsonContinuation(ContType::OBJECT, propertyList.size());
93 
94                     SkipStartWhiteSpace();
95                     if (UNLIKELY(*current_ != '"')) {
96                         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object Prop in JSON",
97                                                       JSTaggedValue::Exception());
98                     }
99                     propertyList.emplace_back(ParseString(true));
100                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
101                     SkipStartWhiteSpace();
102                     if (UNLIKELY(*current_ != ':')) {
103                         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON",
104                                                       JSTaggedValue::Exception());
105                     }
106                     Advance();
107                     continue;
108                 case Tokens::MAP:
109                     if (EmptyObjectCheck()) {
110                         if (transformType_ == TransformType::SENDABLE) {
111                             parseValue = JSHandle<JSTaggedValue>(CreateSharedMap());
112                         } else {
113                             parseValue = JSHandle<JSTaggedValue>(CreateMap());
114                         }
115                         GetNextNonSpaceChar();
116                         break;
117                     }
118                     continuationList.emplace_back(std::move(continuation));
119                     continuation = JsonContinuation(ContType::MAP, propertyList.size());
120 
121                     SkipStartWhiteSpace();
122                     if (UNLIKELY(*current_ != '"')) {
123                         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected MAP Prop in JSON",
124                                                       JSTaggedValue::Exception());
125                     }
126                     propertyList.emplace_back(ParseString(true));
127                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
128                     SkipStartWhiteSpace();
129                     if (UNLIKELY(*current_ != ':')) {
130                         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected MAP in JSON",
131                                                       JSTaggedValue::Exception());
132                     }
133                     Advance();
134                     continue;
135                 case Tokens::ARRAY:
136                     if (EmptyArrayCheck()) {
137                         if (transformType_ == TransformType::SENDABLE) {
138                             parseValue = JSHandle<JSTaggedValue>(factory_->NewJSSArray());
139                         } else {
140                             parseValue = JSHandle<JSTaggedValue>(factory_->NewJSArray(0, initialJSArrayClass_));
141                         }
142                         GetNextNonSpaceChar();
143                         break;
144                     }
145                     continuationList.emplace_back(std::move(continuation));
146                     continuation = JsonContinuation(ContType::ARRAY, elementsList.size());
147                     continue;
148                 case Tokens::LITERAL_TRUE:
149                     parseValue = JSHandle<JSTaggedValue>(thread_, ParseLiteralTrue());
150                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
151                     break;
152                 case Tokens::LITERAL_FALSE:
153                     parseValue = JSHandle<JSTaggedValue>(thread_, ParseLiteralFalse());
154                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
155                     break;
156                 case Tokens::LITERAL_NULL:
157                     parseValue = JSHandle<JSTaggedValue>(thread_, ParseLiteralNull());
158                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
159                     break;
160                 case Tokens::NUMBER:
161                     parseValue = JSHandle<JSTaggedValue>(thread_,
162                                                          ParseNumber(IsInObjOrArrayOrMap(continuation.type_)));
163                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
164                     break;
165                 case Tokens::STRING:
166                     parseValue = ParseString(IsInObjOrArrayOrMap(continuation.type_));
167                     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
168                     break;
169                 default:
170                     THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: Invalid Token",
171                                                   JSTaggedValue::Exception());
172             }
173             break;
174         }
175 
176         while (true) {
177             switch (continuation.type_) {
178                 case ContType::RETURN:
179                     ASSERT(continuationList.empty());
180                     ASSERT(elementsList.empty());
181                     ASSERT(propertyList.empty());
182                     if (current_ <= range_) {
183                         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: Remaining Text Before Return",
184                                                       JSTaggedValue::Exception());
185                     }
186                     return parseValue.GetTaggedValue();
187                 case ContType::ARRAY: {
188                     elementsList.emplace_back(parseValue);
189                     SkipStartWhiteSpace();
190                     if (*current_ == ',') {
191                         Advance();
192                         break;
193                     }
194                     if (transformType_ == TransformType::SENDABLE) {
195                         parseValue = CreateSJsonArray(continuation, elementsList);
196                     } else {
197                         parseValue = CreateJsonArray(continuation, elementsList);
198                     }
199                     if (*current_ != ']') {
200                         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON",
201                                                       JSTaggedValue::Exception());
202                     }
203                     Advance();
204                     elementsList.resize(continuation.index_);
205                     continuation = std::move(continuationList.back());
206                     continuationList.pop_back();
207                     continue;
208                 }
209                 case ContType::OBJECT: {
210                     propertyList.emplace_back(parseValue);
211                     SkipStartWhiteSpace();
212                     if (*current_ == ',') {
213                         GetNextNonSpaceChar();
214                         if (UNLIKELY(*current_ != '"')) {
215                             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object Prop in JSON",
216                                                           JSTaggedValue::Exception());
217                         }
218                         propertyList.emplace_back(ParseString(true));
219                         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
220                         SkipStartWhiteSpace();
221                         if (UNLIKELY(*current_ != ':')) {
222                             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON",
223                                                           JSTaggedValue::Exception());
224                         }
225                         Advance();
226                         break;
227                     }
228                     if (UNLIKELY(transformType_ == TransformType::SENDABLE)) {
229                         parseValue = CreateSJsonObject<isEnableCMCGC>(continuation, propertyList);
230                     } else {
231                         parseValue = CreateJsonObject<isEnableCMCGC>(continuation, propertyList);
232                     }
233                     if (UNLIKELY(*current_ != '}')) {
234                         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON",
235                                                       JSTaggedValue::Exception());
236                     }
237                     Advance();
238                     propertyList.resize(continuation.index_);
239                     continuation = std::move(continuationList.back());
240                     continuationList.pop_back();
241                     continue;
242                 }
243                 case ContType::MAP: {
244                     propertyList.emplace_back(parseValue);
245                     SkipStartWhiteSpace();
246                     if (*current_ == ',') {
247                         GetNextNonSpaceChar();
248                         if (UNLIKELY(*current_ != '"')) {
249                             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected MAP Prop in JSON",
250                                                           JSTaggedValue::Exception());
251                         }
252                         propertyList.emplace_back(ParseString(true));
253                         RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
254                         SkipStartWhiteSpace();
255                         if (UNLIKELY(*current_ != ':')) {
256                             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected MAP in JSON",
257                                                           JSTaggedValue::Exception());
258                         }
259                         Advance();
260                         break;
261                     }
262                     if (UNLIKELY(transformType_ == TransformType::SENDABLE)) {
263                         parseValue = CreateSJsonMap(continuation, propertyList);
264                     } else {
265                         parseValue = CreateJsonMap(continuation, propertyList);
266                     }
267                     if (UNLIKELY(*current_ != '}')) {
268                         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected MAP in JSON",
269                                                       JSTaggedValue::Exception());
270                     }
271                     Advance();
272                     propertyList.resize(continuation.index_);
273                     continuation = std::move(continuationList.back());
274                     continuationList.pop_back();
275                     continue;
276                 }
277             }
278             break;
279         }
280         if constexpr (isEnableCMCGC) {
281             thread_->CheckSafepointIfSuspended();
282         }
283     }
284 }
285 
286 template<typename T>
CreateJsonArray(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & elementsList)287 JSHandle<JSTaggedValue> JsonParser<T>::CreateJsonArray(JsonContinuation continuation,
288     std::vector<JSHandle<JSTaggedValue>> &elementsList)
289 {
290     size_t start = continuation.index_;
291     size_t size = elementsList.size() - start;
292     JSHandle<JSArray> array = factory_->NewJSArray(size, initialJSArrayClass_);
293     JSHandle<TaggedArray> elements = factory_->NewJsonFixedArray(start, size, elementsList);
294     JSHandle<JSObject> obj(array);
295     obj->SetElements(thread_, elements);
296     return JSHandle<JSTaggedValue>(array);
297 }
298 
299 template<typename T>
CreateSJsonArray(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & elementsList)300 JSHandle<JSTaggedValue> JsonParser<T>::CreateSJsonArray([[maybe_unused]] JsonContinuation continuation,
301     [[maybe_unused]] std::vector<JSHandle<JSTaggedValue>> &elementsList)
302 {
303     size_t start = continuation.index_;
304     size_t size = elementsList.size() - start;
305     JSHandle<JSSharedArray> array = factory_->NewJSSArray();
306     array->SetArrayLength(thread_, size);
307     JSHandle<TaggedArray> elements = factory_->NewSJsonFixedArray(start, size, elementsList);
308     JSHandle<JSObject> obj(array);
309     obj->SetElements(thread_, elements);
310     return JSHandle<JSTaggedValue>(array);
311 }
312 
313 template<typename T>
314 template<bool isEnableCMCGC>
CreateJsonObject(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & propertyList)315 JSHandle<JSTaggedValue> JsonParser<T>::CreateJsonObject(JsonContinuation continuation,
316     std::vector<JSHandle<JSTaggedValue>> &propertyList)
317 {
318     size_t start = continuation.index_;
319     size_t size = propertyList.size() - start;
320     auto obj = JSHandle<JSTaggedValue>(factory_->NewJSObject(initialJSObjectClass_));
321     for (size_t i = 0; i < size; i += 2) { // 2: prop name and value
322         auto &keyHandle = propertyList[start + i];
323         auto &valueHandle = propertyList[start + i + 1];
324         auto res = SetPropertyByValue(obj, keyHandle, valueHandle);
325         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_);
326         if (res.IsHole()) {
327             // slow path
328             JSTaggedValue::SetProperty(thread_, obj, keyHandle, valueHandle, true);
329             RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_);
330         }
331         if constexpr (isEnableCMCGC) {
332             thread_->CheckSafepointIfSuspended();
333         }
334     }
335     return obj;
336 }
337 
338 template<typename T>
339 template<bool isEnableCMCGC>
CreateSJsonObject(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & propertyList)340 JSHandle<JSTaggedValue> JsonParser<T>::CreateSJsonObject(JsonContinuation continuation,
341     std::vector<JSHandle<JSTaggedValue>> &propertyList)
342 {
343     size_t start = continuation.index_;
344     size_t size = propertyList.size() - start;
345     uint32_t fieldNum = size / 2; // 2: key-value pair
346     JSHandle<JSHClass> hclass;
347     JSHandle<LayoutInfo> layout;
348     JSHandle<JSTaggedValue> jsonPrototype = GetSJsonPrototype();
349     if (fieldNum == 0) {
350         layout = factory_->CreateSLayoutInfo(fieldNum);
351         hclass = factory_->NewSEcmaHClass(JSSharedObject::SIZE, fieldNum, JSType::JS_SHARED_OBJECT,
352                                           JSHandle<JSTaggedValue>(jsonPrototype), JSHandle<JSTaggedValue>(layout));
353         JSHandle<JSObject> obj = factory_->NewSharedOldSpaceJSObject(hclass);
354         return JSHandle<JSTaggedValue>(obj);
355     } else if (LIKELY(fieldNum <= JSSharedObject::MAX_INLINE)) {
356         layout = factory_->CreateSLayoutInfo(fieldNum);
357         JSHandle<TaggedArray> propertyArray = factory_->NewSTaggedArray(size);
358         for (size_t i = 0; i < size; i += 2) { // 2: prop name and value
359             JSHandle<JSTaggedValue> keyHandle = propertyList[start + i];
360             auto newKey = keyHandle.GetTaggedValue();
361             auto stringAccessor = EcmaStringAccessor(newKey);
362             if (!stringAccessor.IsInternString()) {
363                 newKey = JSTaggedValue(thread_->GetEcmaVM()->GetFactory()->InternString(keyHandle));
364             }
365             propertyArray->Set(thread_, i, newKey);
366             propertyArray->Set(thread_, i + 1, JSTaggedValue(int(FieldType::NONE)));
367             if constexpr (isEnableCMCGC) {
368                 thread_->CheckSafepointIfSuspended();
369             }
370         }
371         hclass = factory_->NewSEcmaHClass(JSSharedObject::SIZE, fieldNum, JSType::JS_SHARED_OBJECT,
372             JSHandle<JSTaggedValue>(jsonPrototype), JSHandle<JSTaggedValue>(layout));
373         JSHandle<NumberDictionary> elementsDic = NumberDictionary::CreateInSharedHeap(thread_);
374         bool hasElement = false;
375         SendableClassDefiner::AddFieldTypeToHClass(thread_, propertyArray, size, layout, hclass, elementsDic,
376                                                    hasElement, start, std::move(propertyList));
377         JSHandle<JSObject> obj = factory_->NewSharedOldSpaceJSObject(hclass);
378         uint32_t index = 0;
379         size = (hclass->GetInlinedProperties() << 1);
380         for (size_t i = 0; i < size; i += 2) { // 2: prop name and value
381             obj->SetPropertyInlinedProps(thread_, index++, propertyList[start + i + 1].GetTaggedValue());
382         }
383         if (hasElement) {
384             JSHandle<TaggedArray> elementsDicHdl(elementsDic);
385             JSHandle<TaggedArray> elements =
386                 factory_->NewAndCopySNameDictionary(elementsDicHdl, elementsDicHdl->GetLength());
387             obj->SetElements(thread_, elements);
388             hclass->SetIsDictionaryElement(true);
389         }
390         return JSHandle<JSTaggedValue>(obj);
391     }
392     // build in dict mode
393     JSMutableHandle<NameDictionary> dict(
394         thread_, NameDictionary::CreateInSharedHeap(thread_, NameDictionary::ComputeHashTableSize(fieldNum)));
395     JSMutableHandle<JSTaggedValue> propKey(thread_, JSTaggedValue::Undefined());
396     JSMutableHandle<JSTaggedValue> propValue(thread_, JSTaggedValue::Undefined());
397     // create dict and set key value
398     for (size_t i = 0; i < size; i += 2) { // 2: prop name and value
399         PropertyAttributes attributes = PropertyAttributes::Default(false, false, false);
400         propKey.Update(propertyList[start + i]);
401         propValue.Update(propertyList[start + i + 1]);
402         JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread_, dict, propKey,
403                                                                        propValue, attributes);
404         dict.Update(newDict);
405     }
406     hclass = factory_->NewSEcmaHClassDictMode(JSSharedObject::SIZE, fieldNum, JSType::JS_SHARED_OBJECT,
407                                               JSHandle<JSTaggedValue>(jsonPrototype));
408     JSHandle<JSObject> obj = factory_->NewSharedOldSpaceJSObject(hclass);
409     obj->SetProperties(thread_, dict);
410     return JSHandle<JSTaggedValue>(obj);
411 }
412 
413 template<typename T>
CreateSharedMap()414 JSHandle<JSSharedMap> JsonParser<T>::CreateSharedMap()
415 {
416     JSHandle<JSTaggedValue> proto = GetSMapPrototype();
417     auto emptySLayout = thread_->GlobalConstants()->GetHandledEmptySLayoutInfo();
418     JSHandle<JSHClass> mapClass = factory_->NewSEcmaHClass(JSSharedMap::SIZE, 0,
419                                                            JSType::JS_SHARED_MAP, proto,
420                                                            emptySLayout);
421     JSHandle<JSObject> obj = factory_->NewSharedOldSpaceJSObjectWithInit(mapClass);
422     JSHandle<JSSharedMap> jsMap = JSHandle<JSSharedMap>::Cast(obj);
423     JSHandle<LinkedHashMap> linkedMap(
424         LinkedHashMap::Create(thread_, LinkedHashMap::MIN_CAPACITY, MemSpaceKind::SHARED));
425     jsMap->SetLinkedMap(thread_, linkedMap);
426     jsMap->SetModRecord(0);
427     return jsMap;
428 }
429 
430 template<typename T>
CreateMap()431 JSHandle<JSMap> JsonParser<T>::CreateMap()
432 {
433     JSHandle<JSTaggedValue> constructor = env_->GetBuiltinsMapFunction();
434     JSHandle<JSMap> map =
435         JSHandle<JSMap>::Cast(factory_->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
436     JSHandle<LinkedHashMap> linkedMap = LinkedHashMap::Create(thread_);
437     map->SetLinkedMap(thread_, linkedMap);
438     return JSHandle<JSMap>(thread_, *map);
439 }
440 
441 template<typename T>
CreateJsonMap(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & propertyList)442 JSHandle<JSTaggedValue> JsonParser<T>::CreateJsonMap(JsonContinuation continuation,
443                                                      std::vector<JSHandle<JSTaggedValue>> &propertyList)
444 {
445     size_t start = continuation.index_;
446     size_t size = propertyList.size() - start;
447     uint32_t fieldNum = size / 2;
448     JSHandle<JSMap> map = CreateMap();
449     if (fieldNum == 0) {
450         return JSHandle<JSTaggedValue>(map);
451     }
452     for (size_t i = 0; i < size; i += 2) { // 2: prop name and value
453         JSMap::Set(thread_, map, propertyList[start + i], propertyList[start + i + 1]);
454         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_);
455     }
456     return JSHandle<JSTaggedValue>(map);
457 }
458 
459 template<typename T>
CreateSJsonMap(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & propertyList)460 JSHandle<JSTaggedValue> JsonParser<T>::CreateSJsonMap(JsonContinuation continuation,
461                                                       std::vector<JSHandle<JSTaggedValue>> &propertyList)
462 {
463     size_t start = continuation.index_;
464     size_t size = propertyList.size() - start;
465     uint32_t fieldNum = size / 2; // 2: key-value pair
466     JSHandle<JSSharedMap> jsMap = CreateSharedMap();
467     if (fieldNum == 0) {
468         return JSHandle<JSTaggedValue>(jsMap);
469     } else if (LIKELY(fieldNum <= JSSharedMap::MAX_INLINE)) {
470         for (size_t i = 0; i < size; i += 2) { // 2: prop name and value
471             JSSharedMap::Set(thread_, jsMap, propertyList[start + i], propertyList[start + i + 1]);
472         }
473         return JSHandle<JSTaggedValue>(jsMap);
474     }
475     // build in dict mode
476     JSMutableHandle<NameDictionary> dict(
477         thread_, NameDictionary::CreateInSharedHeap(thread_, NameDictionary::ComputeHashTableSize(fieldNum)));
478     JSMutableHandle<JSTaggedValue> propKey(thread_, JSTaggedValue::Undefined());
479     JSMutableHandle<JSTaggedValue> propValue(thread_, JSTaggedValue::Undefined());
480     // create dict and set key value
481     for (size_t i = 0; i < size; i += 2) { // 2: prop name and value
482         PropertyAttributes attributes = PropertyAttributes::Default(false, false, false);
483         propKey.Update(propertyList[start + i]);
484         propValue.Update(propertyList[start + i + 1]);
485         JSHandle<NameDictionary> newDict = NameDictionary::PutIfAbsent(thread_, dict, propKey,
486                                                                        propValue, attributes);
487         dict.Update(newDict);
488     }
489     jsMap->SetProperties(thread_, dict);
490     return JSHandle<JSTaggedValue>(jsMap);
491 }
492 
493 template<typename T>
SetPropertyByValue(const JSHandle<JSTaggedValue> & receiver,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)494 JSTaggedValue JsonParser<T>::SetPropertyByValue(const JSHandle<JSTaggedValue> &receiver,
495     const JSHandle<JSTaggedValue> &key, const JSHandle<JSTaggedValue> &value)
496 {
497     ASSERT(key->IsString());
498     auto newKey = key.GetTaggedValue();
499     auto stringAccessor = EcmaStringAccessor(newKey);
500     if (!stringAccessor.IsLineString() || (stringAccessor.IsUtf8() &&
501         IsNumberCharacter(*stringAccessor.GetDataUtf8()))) {
502         uint32_t index = 0;
503         if (stringAccessor.ToElementIndex(thread_, &index)) {
504             return ObjectFastOperator::SetPropertyByIndex<ObjectFastOperator::Status::UseOwn>(thread_,
505                 receiver.GetTaggedValue(), index, value.GetTaggedValue());
506         }
507     }
508     if (!stringAccessor.IsInternString()) {
509         newKey = JSTaggedValue(thread_->GetEcmaVM()->GetFactory()->InternString(key));
510     }
511     return ObjectFastOperator::SetJsonPropertyByName(thread_, receiver.GetTaggedValue(),
512                                                      newKey, value.GetTaggedValue());
513 }
514 
515 template<typename T>
ParseNumber(bool inObjorArr)516 JSTaggedValue JsonParser<T>::ParseNumber(bool inObjorArr)
517 {
518     if (inObjorArr) {
519         bool isFast = true;
520         int32_t fastInteger = 0;
521         bool isNumber = ReadNumberRange(isFast, fastInteger);
522         if (!isNumber) {
523             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON Array Or Object",
524                                           JSTaggedValue::Exception());
525         }
526         if (isFast) {
527             return parseOptions_.bigIntMode == BigIntMode::ALWAYS_PARSE_AS_BIGINT ?
528                 BigInt::Int32ToBigInt(thread_, fastInteger).GetTaggedValue() : JSTaggedValue(fastInteger);
529         }
530     }
531 
532     Text current = current_;
533     bool negative = false;
534     bool hasExponent = false;
535     bool hasDecimal = false;
536     if (*current_ == '-') {
537         if (UNLIKELY(current_++ == end_)) {
538             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
539         }
540         negative = true;
541     }
542     if (*current_ == '0') {
543         if (!CheckZeroBeginNumber(hasExponent, hasDecimal)) {
544             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
545         }
546     } else if (*current_ >= '1' && *current_ <= '9') {
547         if (!CheckNonZeroBeginNumber(hasExponent, hasDecimal)) {
548             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
549         }
550     } else {
551         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception());
552     }
553 
554     std::string strNum(current, end_ + 1);
555     current_ = end_ + 1;
556     return ConvertToNumber(strNum, negative, hasExponent, hasDecimal);
557 }
558 
559 template<typename T>
ConvertToNumber(const std::string & str,bool negative,bool hasExponent,bool hasDecimal)560 JSTaggedValue JsonParser<T>::ConvertToNumber(const std::string &str, bool negative, bool hasExponent, bool hasDecimal)
561 {
562     errno = 0; // reset errno to 0 to avoid errno has been changed
563     double v = std::strtod(str.c_str(), nullptr);
564     if (errno == ERANGE) {
565         // errno is ERANGE mean double value greater than DBL_MAX(1.79e+308) or less than DBL_MIN(2.22e-308),
566         // by compromising precision, std::strtod support representation allows even smaller
567         // values up to about 5e-324(Number.MIN_VALUE).
568         errno = 0;
569         return JSTaggedValue(v);
570     }
571     errno = 0;
572     if (negative && v == 0) {
573         return JSTaggedValue(-0.0);
574     }
575     if (parseOptions_.bigIntMode == BigIntMode::DEFAULT) {
576         return JSTaggedValue::TryCastDoubleToInt32(v);
577     }
578     if (NumberHelper::IsSafeIntegerNumber(v)) {
579         if (parseOptions_.bigIntMode == BigIntMode::ALWAYS_PARSE_AS_BIGINT) {
580             if (v == 0.0) {
581                 return BigInt::Int32ToBigInt(thread_, 0).GetTaggedValue();
582             }
583             JSTaggedValue value = BigInt::DoubleToBigInt(thread_, v);
584             RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_);
585             if (value.IsBigInt()) {
586                 return value;
587             }
588             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: ConvertToNumber Fail",
589                                           JSTaggedValue::Exception());
590         }
591         return JSTaggedValue::TryCastDoubleToInt32(v);
592     } else {
593         return (hasExponent || hasDecimal) ? JSTaggedValue::TryCastDoubleToInt32(v) :
594             NumberHelper::StringToBigInt(thread_, JSHandle<JSTaggedValue>::Cast(factory_->NewFromStdString(str)));
595     }
596 }
597 
598 template<typename T>
ParseStringLength(size_t & length,bool & isAscii,bool inObjOrArrOrMap)599 bool JsonParser<T>::ParseStringLength(size_t &length, bool &isAscii, bool inObjOrArrOrMap)
600 {
601     Text last = inObjOrArrOrMap ? range_ : end_;
602     for (Text current = current_; current < last; ++current) {
603         T c = *current;
604         if (inObjOrArrOrMap && c == '"') {
605             end_ = current;
606             return true;
607         } else if (c == '\\') {
608             if (UNLIKELY(!CheckBackslash(current, last, isAscii))) {
609                 return false;
610             }
611         } else if (UNLIKELY(c < CODE_SPACE)) {
612             return false;
613         } else if (c > ASCII_END) {
614             ASSERT(sizeof(T) == sizeof(uint16_t));
615             isAscii = false;
616         }
617         ++length;
618     }
619     return !inObjOrArrOrMap;
620 }
621 
622 template<typename T>
CheckBackslash(Text & text,Text last,bool & isAscii)623 bool JsonParser<T>::CheckBackslash(Text &text, Text last, bool &isAscii)
624 {
625     ASSERT(*text == '\\');
626     ++text;
627     if (text >= last) {
628         return false;
629     }
630     switch (*text) {
631         case '\"':
632         case '\\':
633         case '/':
634         case 'b':
635         case 'f':
636         case 'n':
637         case 'r':
638         case 't':
639             break;
640         case 'u': {
641             if (text + UNICODE_DIGIT_LENGTH >= last) {
642                 return false;
643             };
644             T ucharFirst = *++text;
645             if (ucharFirst == '0') {
646                 // do nothing
647             } else if ((ucharFirst >= '1' && ucharFirst <= '9') ||
648                         (ucharFirst >= 'A' && ucharFirst <= 'F') || (ucharFirst >= 'a' && ucharFirst <= 'f')) {
649                 isAscii = false;  // >= \u1000
650             } else {
651                 return false;
652             }
653             T ucharSecond = *++text;
654             if (ucharSecond == '0') {
655                 // do nothing
656             } else if ((ucharSecond >= '1' && ucharSecond <= '9') ||
657                         (ucharSecond >= 'A' && ucharSecond <= 'F') || (ucharSecond >= 'a' && ucharSecond <= 'f')) {
658                 isAscii = false;  // >= \u0100
659             } else {
660                 return false;
661             }
662             bool thirdZero = false;
663             T ucharThird = *++text;
664             if (ucharThird == '0') {
665                 thirdZero = true;
666             } else if (ucharThird >= '1' && ucharThird <= '7') {
667                 // do nothing
668             } else if ((ucharThird >= '8' && ucharThird <= '9') ||
669                         (ucharThird >= 'A' && ucharThird <= 'F') || (ucharThird >= 'a' && ucharThird <= 'f')) {
670                 isAscii = false;  // >= \u0080
671             } else {
672                 return false;
673             }
674             T ucharFourth = *++text;
675             if (thirdZero && ucharFourth == '0') {
676                 isAscii = false;  // \uxx00
677             } else if ((ucharFourth >= '0' && ucharFourth <= '9') ||
678                         (ucharFourth >= 'A' && ucharFourth <= 'F') || (ucharFourth >= 'a' && ucharFourth <= 'f')) {
679                 // do nothing
680             } else {
681                 return false;
682             }
683             break;
684         }
685         default:
686             return false;
687     }
688     return true;
689 }
690 
691 template<typename T>
692 template<typename Char>
ParseBackslash(Char * & p)693 void JsonParser<T>::ParseBackslash(Char *&p)
694 {
695     ASSERT(current_ < end_);
696     Advance();
697     switch (*current_) {
698         case '\"':
699             *p++ = '\"';
700             break;
701         case '\\':
702             *p++ = '\\';
703             break;
704         case '/':
705             *p++ = '/';
706             break;
707         case 'b':
708             *p++ = '\b';
709             break;
710         case 'f':
711             *p++ = '\f';
712             break;
713         case 'n':
714             *p++ = '\n';
715             break;
716         case 'r':
717             *p++ = '\r';
718             break;
719         case 't':
720             *p++ = '\t';
721             break;
722         case 'u': {
723             ASSERT(end_ - current_ >= UNICODE_DIGIT_LENGTH);
724             uint16_t res = 0;
725             for (size_t pos = 0; pos < UNICODE_DIGIT_LENGTH; pos++) {
726                 Advance();
727                 T uchar = *current_;
728                 if (uchar >= '0' && uchar <= '9') {
729                     res *= NUMBER_SIXTEEN;
730                     res += (uchar - '0');
731                 } else if (uchar >= 'a' && uchar <= 'f') {
732                     res *= NUMBER_SIXTEEN;
733                     res += (uchar - 'a' + NUMBER_TEN);
734                 } else if (uchar >= 'A' && uchar <= 'F') {
735                     res *= NUMBER_SIXTEEN;
736                     res += (uchar - 'A' + NUMBER_TEN);
737                 } else {
738                     UNREACHABLE();
739                 }
740             }
741             ASSERT(sizeof(Char) == sizeof(uint16_t) || res <= ASCII_END);
742             *p++ = static_cast<Char>(res);
743             break;
744         }
745         default:
746             UNREACHABLE();
747     }
748 }
749 
750 template<typename T>
751 template<typename Char>
CopyCharWithBackslash(Char * & p)752 void JsonParser<T>::CopyCharWithBackslash(Char *&p)
753 {
754     while (current_ <= end_) {
755         T c = *current_;
756         ASSERT(c >= CODE_SPACE);
757         ASSERT(sizeof(Char) == sizeof(uint16_t) || c <= ASCII_END);
758         if (c == '\\') {
759             ParseBackslash(p);
760         } else {
761             *p++ = c;
762         }
763         Advance();
764     }
765 }
766 
767 template<typename T>
ParseStringWithBackslash(bool inObjOrArrOrMap)768 JSHandle<JSTaggedValue> JsonParser<T>::ParseStringWithBackslash(bool inObjOrArrOrMap)
769 {
770     size_t length = 0;
771     bool isAscii = true;
772     if (UNLIKELY(!ParseStringLength(length, isAscii, inObjOrArrOrMap))) {
773         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected string in JSON",
774             JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Exception()));
775     }
776     end_--;
777     if (isAscii) {
778         EcmaString *str = EcmaStringAccessor::CreateLineString(thread_->GetEcmaVM(), length, true);
779         uint8_t *data = const_cast<uint8_t *>(EcmaStringAccessor(str).GetDataUtf8());
780         uint8_t *p = data;
781         CopyCharWithBackslash(p);
782         ASSERT(p - data == length);
783         Advance();
784         return JSHandle<JSTaggedValue>(thread_, str);
785     } else {
786         EcmaString *str = EcmaStringAccessor::CreateLineString(thread_->GetEcmaVM(), length, false);
787         uint16_t *data = const_cast<uint16_t *>(EcmaStringAccessor(str).GetDataUtf16());
788         uint16_t *p = data;
789         CopyCharWithBackslash(p);
790         ASSERT(p - data == length);
791         Advance();
792         return JSHandle<JSTaggedValue>(thread_, str);
793     }
794 }
795 
796 template<typename T>
SkipEndWhiteSpace()797 void JsonParser<T>::SkipEndWhiteSpace()
798 {
799     while (current_ != end_) {
800         if (*end_ == ' ' || *end_ == '\r' || *end_ == '\n' || *end_ == '\t') {
801             end_--;
802         } else {
803             break;
804         }
805     }
806 }
807 
808 template<typename T>
SkipStartWhiteSpace()809 void JsonParser<T>::SkipStartWhiteSpace()
810 {
811     while (current_ != end_) {
812         if (*current_ == ' ' || *current_ == '\r' || *current_ == '\n' || *current_ == '\t') {
813             Advance();
814         } else {
815             break;
816         }
817     }
818 }
819 
820 template<typename T>
GetNextNonSpaceChar()821 void JsonParser<T>::GetNextNonSpaceChar()
822 {
823     Advance();
824     SkipStartWhiteSpace();
825 }
826 
827 template<typename T>
ParseToken()828 Tokens JsonParser<T>::ParseToken()
829 {
830     switch (*current_) {
831         case '{':
832             return parseOptions_.returnType == ParseReturnType::MAP ? Tokens::MAP : Tokens::OBJECT;
833         case '[':
834             return Tokens::ARRAY;
835         case '"':
836             return Tokens::STRING;
837         case '0':
838         case '1':
839         case '2':
840         case '3':
841         case '4':
842         case '5':
843         case '6':
844         case '7':
845         case '8':
846         case '9':
847         case '-':
848             return Tokens::NUMBER;
849         case 't':
850             return Tokens::LITERAL_TRUE;
851         case 'f':
852             return Tokens::LITERAL_FALSE;
853         case 'n':
854             return Tokens::LITERAL_NULL;
855         default:
856             return Tokens::TOKEN_ILLEGAL;
857     }
858 }
859 
860 template<typename T>
ParseLiteralTrue()861 JSTaggedValue JsonParser<T>::ParseLiteralTrue()
862 {
863     static const char literalTrue[] = "true";
864     uint32_t remainingLength = range_ - current_;
865     if (UNLIKELY(remainingLength < 3)) { // 3: literalTrue length - 1
866         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: ParseLiteralTrue Fail",
867                                       JSTaggedValue::Exception());
868     }
869     bool isMatch = MatchText(literalTrue, 4); // 4: literalTrue length
870     if (LIKELY(isMatch)) {
871         return JSTaggedValue::True();
872     }
873     THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: ParseLiteralTrue Fail",
874                                   JSTaggedValue::Exception());
875 }
876 
877 template<typename T>
ParseLiteralFalse()878 JSTaggedValue JsonParser<T>::ParseLiteralFalse()
879 {
880     static const char literalFalse[] = "false";
881     uint32_t remainingLength = range_ - current_;
882     if (UNLIKELY(remainingLength < 4)) { // 4: literalFalse length - 1
883         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: ParseLiteralFalse Fail",
884                                       JSTaggedValue::Exception());
885     }
886     bool isMatch = MatchText(literalFalse, 5); // 5: literalFalse length
887     if (LIKELY(isMatch)) {
888         return JSTaggedValue::False();
889     }
890     THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: ParseLiteralFalse Fail",
891                                   JSTaggedValue::Exception());
892 }
893 
894 template<typename T>
ParseLiteralNull()895 JSTaggedValue JsonParser<T>::ParseLiteralNull()
896 {
897     static const char literalNull[] = "null";
898     uint32_t remainingLength = range_ - current_;
899     if (UNLIKELY(remainingLength < 3)) { // 3: literalNull length - 1
900         THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: ParseLiteralNull Fail",
901                                       JSTaggedValue::Exception());
902     }
903     bool isMatch = MatchText(literalNull, 4); // 4: literalNull length
904     if (LIKELY(isMatch)) {
905         return JSTaggedValue::Null();
906     }
907     THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON: ParseLiteralNull Fail",
908                                   JSTaggedValue::Exception());
909 }
910 
911 template<typename T>
MatchText(const char * str,uint32_t matchLen)912 bool JsonParser<T>::MatchText(const char *str, uint32_t matchLen)
913 {
914     // first char is already matched
915     for (uint32_t pos = 1; pos < matchLen; ++pos) {
916         if (current_[pos] != str[pos]) {
917             return false;
918         }
919     }
920     current_ += matchLen;
921     return true;
922 }
923 
924 template<typename T>
ReadNumberRange(bool & isFast,int32_t & fastInteger)925 bool JsonParser<T>::ReadNumberRange(bool &isFast, int32_t &fastInteger)
926 {
927     Text current = current_;
928     int32_t sign = 1;
929     if (*current == '-') {
930         current++;
931         sign = -1;
932     }
933 
934     if (*current == '0') {
935         isFast = false;
936         current++;
937     } else {
938         Text advance = AdvanceLastNumberCharacter(current);
939         if (UNLIKELY(current == advance)) {
940             return false;
941         }
942         size_t numberLength = advance - current;
943         int32_t i = 0;
944         if (numberLength <= INTEGER_MAX_LEN && (*advance == ',' || *advance == ']' || *advance == '}')) {
945             for (; current != advance; current++) {
946                 i = (i * 10U) + ((*current) - '0');
947             }
948             fastInteger = i * sign;
949             current_ = advance;
950             return true;
951         }
952         isFast = false;
953     }
954 
955     while (current != range_) {
956         if (IsNumberCharacter(*current)) {
957             current++;
958             continue;
959         } else if (IsNumberSignalCharacter(*current)) {
960             isFast = false;
961             current++;
962             continue;
963         }
964         Text end = current;
965         while (current != range_) {
966             if (*current == ' ' || *current == '\r' || *current == '\n' || *current == '\t') {
967                 current++;
968             } else if (*current == ',' || *current == ']' || *current == '}') {
969                 end_ = end - 1;
970                 return true;
971             } else {
972                 return false;
973             }
974         }
975         if (*current == ']' || *current == '}') {
976             end_ = end - 1;
977             return true;
978         }
979         return false;
980     }
981     end_ = range_ - 1;
982     return true;
983 }
984 
985 template<typename T>
AdvanceLastNumberCharacter(Text current)986 typename JsonParser<T>::Text JsonParser<T>::AdvanceLastNumberCharacter(Text current)
987 {
988     return std::find_if(current, range_, [this](T c) { return !IsNumberCharacter(c); });
989 }
990 
991 template<typename T>
IsNumberCharacter(T ch)992 bool JsonParser<T>::IsNumberCharacter(T ch)
993 {
994     if (ch >= '0' && ch <= '9') {
995         return true;
996     }
997     return false;
998 }
999 
1000 template<typename T>
IsNumberSignalCharacter(T ch)1001 bool JsonParser<T>::IsNumberSignalCharacter(T ch)
1002 {
1003     return ch == '.' || ch == 'e' || ch == 'E' || ch == '+' || ch == '-';
1004 }
1005 
1006 template<typename T>
IsExponentNumber()1007 bool JsonParser<T>::IsExponentNumber()
1008 {
1009     if (IsNumberCharacter(*current_)) {
1010         return true;
1011     } else if (*current_ == '-' || *current_ == '+') {
1012         if (current_ == end_) {
1013             return false;
1014         }
1015         Advance();
1016         if (IsNumberCharacter(*current_)) {
1017             return true;
1018         }
1019     }
1020     return false;
1021 }
1022 
1023 template<typename T>
IsDecimalsLegal(bool & hasExponent)1024 bool JsonParser<T>::IsDecimalsLegal(bool &hasExponent)
1025 {
1026     if (current_ == end_ && !IsNumberCharacter(*++current_)) {
1027         return false;
1028     }
1029 
1030     while (current_ != end_) {
1031         Advance();
1032         if (IsNumberCharacter(*current_)) {
1033             continue;
1034         } else if (*current_ == 'e' || *current_ == 'E') {
1035             if (hasExponent || current_ == end_) {
1036                 return false;
1037             }
1038             Advance();
1039             if (!IsExponentNumber()) {
1040                 return false;
1041             }
1042             hasExponent = true;
1043         } else {
1044             return false;
1045         }
1046     }
1047     return true;
1048 }
1049 
1050 template<typename T>
IsExponentLegal(bool & hasExponent)1051 bool JsonParser<T>::IsExponentLegal(bool &hasExponent)
1052 {
1053     if (hasExponent || current_ == end_) {
1054         return false;
1055     }
1056     Advance();
1057     if (!IsExponentNumber()) {
1058         return false;
1059     }
1060     while (current_ != end_) {
1061         if (!IsNumberCharacter(*current_)) {
1062             return false;
1063         }
1064         Advance();
1065     }
1066     return true;
1067 }
1068 
1069 template<typename T>
CheckZeroBeginNumber(bool & hasExponent,bool & hasDecimal)1070 bool JsonParser<T>::CheckZeroBeginNumber(bool &hasExponent, bool &hasDecimal)
1071 {
1072     if (current_++ != end_) {
1073         if (*current_ == '.') {
1074             hasDecimal = true;
1075             if (!IsDecimalsLegal(hasExponent)) {
1076                 return false;
1077             }
1078         } else if (*current_ == 'e' || *current_ == 'E') {
1079             if (!IsExponentLegal(hasExponent)) {
1080                 return false;
1081             }
1082         } else {
1083             return false;
1084         }
1085     }
1086     return true;
1087 }
1088 
1089 template<typename T>
CheckNonZeroBeginNumber(bool & hasExponent,bool & hasDecimal)1090 bool JsonParser<T>::CheckNonZeroBeginNumber(bool &hasExponent, bool &hasDecimal)
1091 {
1092     while (current_ != end_) {
1093         Advance();
1094         if (IsNumberCharacter(*current_)) {
1095             continue;
1096         } else if (*current_ == '.') {
1097             hasDecimal = true;
1098             if (!IsDecimalsLegal(hasExponent)) {
1099                 return false;
1100             }
1101         } else if (*current_ == 'e' || *current_ == 'E') {
1102             if (!IsExponentLegal(hasExponent)) {
1103                 return false;
1104             }
1105         } else {
1106             return false;
1107         }
1108     }
1109     return true;
1110 }
1111 
Parse(const JSHandle<EcmaString> & strHandle)1112 JSHandle<JSTaggedValue> Utf8JsonParser::Parse(const JSHandle<EcmaString> &strHandle)
1113 {
1114     ASSERT(*strHandle != nullptr);
1115     auto stringAccessor = EcmaStringAccessor(strHandle);
1116     uint32_t len = stringAccessor.GetLength();
1117     ASSERT(len != UINT32_MAX);
1118 
1119     uint32_t slicedOffset = 0;
1120     if (LIKELY(stringAccessor.IsLineString())) {
1121         sourceString_ = strHandle;
1122     } else if (stringAccessor.IsSlicedString()) {
1123         auto *sliced = static_cast<SlicedEcmaString *>(*strHandle);
1124         slicedOffset = sliced->GetStartIndex();
1125         sourceString_ = JSHandle<EcmaString>(thread_, EcmaString::Cast(sliced->GetParent(thread_)));
1126     } else {
1127         auto *flatten = EcmaStringAccessor::Flatten(thread_->GetEcmaVM(), strHandle);
1128         sourceString_ = JSHandle<EcmaString>(thread_, flatten);
1129     }
1130     begin_ = EcmaStringAccessor(sourceString_).GetDataUtf8();
1131     auto *heap = const_cast<Heap *>(thread_->GetEcmaVM()->GetHeap());
1132     auto listenerId = heap->AddGCListener(UpdatePointersListener, this);
1133     auto res = Launch(begin_ + slicedOffset, begin_ + slicedOffset + len);
1134     heap->RemoveGCListener(listenerId);
1135     return res;
1136 }
1137 
ParticalParseString(std::string & str,Text current,Text nextCurrent)1138 void Utf8JsonParser::ParticalParseString(std::string& str, Text current, Text nextCurrent)
1139 {
1140     str += std::string_view(reinterpret_cast<const char *>(current), nextCurrent - current);
1141 }
1142 
UpdatePointersListener(void * utf8Parser)1143 void Utf8JsonParser::UpdatePointersListener(void *utf8Parser)
1144 {
1145     auto *parser = reinterpret_cast<Utf8JsonParser *>(utf8Parser);
1146     auto *begin = EcmaStringAccessor(parser->sourceString_).GetDataUtf8();
1147     if (parser->begin_ != begin) {
1148         uint32_t currentOffset = parser->current_ - parser->begin_;
1149         uint32_t endOffset = parser->end_ - parser->begin_;
1150         uint32_t rangeOffset = parser->range_ - parser->begin_;
1151         parser->current_ = reinterpret_cast<uint8_t *>(ToUintPtr(begin) + currentOffset);
1152         parser->end_ = reinterpret_cast<uint8_t *>(ToUintPtr(begin) + endOffset);
1153         parser->range_ = reinterpret_cast<uint8_t *>(ToUintPtr(begin) + rangeOffset);
1154         parser->begin_ = begin;
1155     }
1156 }
1157 
ParseString(bool inObjOrArrOrMap)1158 JSHandle<JSTaggedValue> Utf8JsonParser::ParseString(bool inObjOrArrOrMap)
1159 {
1160     bool isFastString = true;
1161     if (inObjOrArrOrMap) {
1162         if (UNLIKELY(!ReadJsonStringRange(isFastString))) {
1163             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON",
1164                 JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Exception()));
1165         }
1166         if (isFastString) {
1167             uint32_t offset = current_ - begin_;
1168             uint32_t strLength = end_ - current_;
1169             ASSERT(strLength <= static_cast<size_t>(UINT32_MAX));
1170             current_ = end_ + 1;
1171             auto *utf8Data = EcmaStringAccessor(sourceString_).GetDataUtf8() + offset;
1172             if (strLength == 1 && EcmaStringAccessor::IsASCIICharacter(utf8Data[0])) {
1173                 int32_t ch = static_cast<int32_t>(utf8Data[0]);
1174                 JSHandle<SingleCharTable> singleCharTable(thread_, thread_->GetSingleCharTable());
1175                 return JSHandle<JSTaggedValue>(thread_, singleCharTable->GetStringFromSingleCharTable(thread_, ch));
1176             }
1177             return JSHandle<JSTaggedValue>::Cast(factory_->NewCompressedUtf8SubString(
1178                 sourceString_, offset, strLength));
1179         }
1180     } else {
1181         if (UNLIKELY(*end_ != '"' || current_ == end_ || !IsFastParseJsonString(isFastString))) {
1182             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON",
1183                 JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Exception()));
1184         }
1185         if (LIKELY(isFastString)) {
1186             uint32_t offset = current_ - begin_;
1187             uint32_t strLength = end_ - current_;
1188             ASSERT(strLength <= static_cast<size_t>(UINT32_MAX));
1189             current_ = end_ + 1;
1190             return JSHandle<JSTaggedValue>::Cast(factory_->NewFromUtf8LiteralCompressSubString(
1191                 sourceString_, offset, strLength));
1192         }
1193     }
1194     return ParseStringWithBackslash(inObjOrArrOrMap);
1195 }
1196 
ReadJsonStringRange(bool & isFastString)1197 bool Utf8JsonParser::ReadJsonStringRange(bool &isFastString)
1198 {
1199     Advance();
1200 #if ENABLE_NEXT_OPTIMIZATION
1201     return JsonPlatformHelper::ReadJsonStringRangeForPlatformForUtf8(isFastString, current_, range_, end_);
1202 #else
1203     // chars are within Ascii
1204     for (Text current = current_; current != range_; ++current) {
1205         uint8_t c = *current;
1206         if (c == '"') {
1207             end_ = current;
1208             return true;
1209         } else if (UNLIKELY(c == '\\')) {
1210             isFastString = false;
1211             // early return for ParseStringWithBackslash
1212             return true;
1213         } else if (UNLIKELY(c < CODE_SPACE)) {
1214             return false;
1215         }
1216     }
1217     return false;
1218 #endif
1219 }
1220 
IsFastParseJsonString(bool & isFastString)1221 bool Utf8JsonParser::IsFastParseJsonString(bool &isFastString)
1222 {
1223     Advance();
1224     // chars are within Ascii
1225     for (Text current = current_; current != end_; ++current) {
1226         if (*current < CODE_SPACE) {
1227             return false;
1228         } else if (*current == '\\') {
1229             isFastString = false;
1230             // early return for ParseStringWithBackslash
1231             return true;
1232         }
1233     }
1234     return true;
1235 }
1236 
Parse(EcmaString * str)1237 JSHandle<JSTaggedValue> Utf16JsonParser::Parse(EcmaString *str)
1238 {
1239     ASSERT(str != nullptr);
1240     uint32_t len = EcmaStringAccessor(str).GetLength();
1241     CVector<uint16_t> buf(len + 1, 0);
1242     EcmaStringAccessor(str).WriteToFlatUtf16(thread_, buf.data(), len);
1243     Text begin = buf.data();
1244     return Launch(begin, begin + len);
1245 }
1246 
ParticalParseString(std::string & str,Text current,Text nextCurrent)1247 void Utf16JsonParser::ParticalParseString(std::string& str, Text current, Text nextCurrent)
1248 {
1249     str += StringHelper::U16stringToString(std::u16string(current, nextCurrent));
1250 }
1251 
ParseString(bool inObjOrArrOrMap)1252 JSHandle<JSTaggedValue> Utf16JsonParser::ParseString(bool inObjOrArrOrMap)
1253 {
1254     bool isFastString = true;
1255     bool isAscii = true;
1256     if (inObjOrArrOrMap) {
1257         if (UNLIKELY(!ReadJsonStringRange(isFastString, isAscii))) {
1258             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON",
1259                 JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Exception()));
1260         }
1261         if (isFastString) {
1262             if (isAscii) {
1263                 std::string value(current_, end_); // from uint16_t* to std::string, can't use std::string_view
1264                 current_ = end_ + 1;
1265                 ASSERT(value.size() <= static_cast<size_t>(UINT32_MAX));
1266                 return JSHandle<JSTaggedValue>::Cast(factory_->NewFromUtf8LiteralCompress(
1267                     reinterpret_cast<const uint8_t *>(value.c_str()), value.size()));
1268             }
1269             std::u16string_view value(reinterpret_cast<const char16_t *>(current_), end_ - current_);
1270             current_ = end_ + 1;
1271             ASSERT(value.size() <= static_cast<size_t>(UINT32_MAX));
1272             return JSHandle<JSTaggedValue>::Cast(factory_->NewFromUtf16LiteralNotCompress(
1273                 reinterpret_cast<const uint16_t *>(value.data()), value.size()));
1274         }
1275     } else {
1276         if (UNLIKELY(*end_ != '"' || current_ == end_ || !IsFastParseJsonString(isFastString, isAscii))) {
1277             THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON",
1278                 JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Exception()));
1279         }
1280         if (LIKELY(isFastString)) {
1281             if (isAscii) {
1282                 std::string value(current_, end_);  // from uint16_t* to std::string, can't use std::string_view
1283                 ASSERT(value.size() <= static_cast<size_t>(UINT32_MAX));
1284                 current_ = end_ + 1;
1285                 return JSHandle<JSTaggedValue>::Cast(factory_->NewFromUtf8LiteralCompress(
1286                     reinterpret_cast<const uint8_t *>(value.c_str()), value.size()));
1287             }
1288             std::u16string_view value(reinterpret_cast<const char16_t *>(current_), end_ - current_);
1289             ASSERT(value.size() <= static_cast<size_t>(UINT32_MAX));
1290             current_ = end_ + 1;
1291             return JSHandle<JSTaggedValue>::Cast(factory_->NewFromUtf16LiteralNotCompress(
1292                 reinterpret_cast<const uint16_t *>(value.data()), value.size()));
1293         }
1294     }
1295     return ParseStringWithBackslash(inObjOrArrOrMap);
1296 }
1297 
ReadJsonStringRange(bool & isFastString,bool & isAscii)1298 bool Utf16JsonParser::ReadJsonStringRange(bool &isFastString, bool &isAscii)
1299 {
1300     Advance();
1301     for (Text current = current_; current != range_; ++current) {
1302         uint16_t c = *current;
1303         if (c == '"') {
1304             end_ = current;
1305             return true;
1306         } else if (UNLIKELY(c == '\\')) {
1307             isFastString = false;
1308             // early return for ParseStringWithBackslash
1309             return true;
1310         }
1311         if (!IsLegalAsciiCharacter(c, isAscii)) {
1312             return false;
1313         }
1314     }
1315     return false;
1316 }
1317 
IsFastParseJsonString(bool & isFastString,bool & isAscii)1318 bool Utf16JsonParser::IsFastParseJsonString(bool &isFastString, bool &isAscii)
1319 {
1320     Advance();
1321     for (Text current = current_; current != end_; ++current) {
1322         if (!IsLegalAsciiCharacter(*current, isAscii)) {
1323             return false;
1324         }
1325         if (*current == '\\') {
1326             isFastString = false;
1327             // early return for ParseStringWithBackslash
1328             return true;
1329         }
1330     }
1331     return true;
1332 }
1333 
IsLegalAsciiCharacter(uint16_t c,bool & isAscii)1334 bool Utf16JsonParser::IsLegalAsciiCharacter(uint16_t c, bool &isAscii)
1335 {
1336     if (c <= ASCII_END) {
1337         return c >= CODE_SPACE ? true : false;
1338     }
1339     isAscii = false;
1340     return true;
1341 }
1342 
InternalizeJsonProperty(JSThread * thread,const JSHandle<JSObject> & holder,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & receiver,TransformType transformType)1343 JSHandle<JSTaggedValue> Internalize::InternalizeJsonProperty(JSThread *thread, const JSHandle<JSObject> &holder,
1344                                                              const JSHandle<JSTaggedValue> &name,
1345                                                              const JSHandle<JSTaggedValue> &receiver,
1346                                                              TransformType transformType)
1347 {
1348     JSHandle<JSTaggedValue> objHandle(holder);
1349     JSHandle<JSTaggedValue> val = JSTaggedValue::GetProperty(thread, objHandle, name).GetValue();
1350     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1351     JSHandle<JSTaggedValue> lengthKey = thread->GlobalConstants()->GetHandledLengthString();
1352     if (val->IsECMAObject()) {
1353         JSHandle<JSObject> obj = JSTaggedValue::ToObject(thread, val);
1354         RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1355         bool isArray = val->IsArray(thread);
1356         if (isArray) {
1357             JSHandle<JSTaggedValue> lenResult = JSTaggedValue::GetProperty(thread, val, lengthKey).GetValue();
1358             RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1359             JSTaggedNumber lenNumber = JSTaggedValue::ToLength(thread, lenResult);
1360             RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1361             uint32_t length = lenNumber.ToUint32();
1362             JSMutableHandle<JSTaggedValue> keyUnknow(thread, JSTaggedValue::Undefined());
1363             JSMutableHandle<JSTaggedValue> keyName(thread, JSTaggedValue::Undefined());
1364             for (uint32_t i = 0; i < length; i++) {
1365                 // Let prop be ! ToString((I)).
1366                 keyUnknow.Update(JSTaggedValue(i));
1367                 keyName.Update(JSTaggedValue::ToString(thread, keyUnknow).GetTaggedValue());
1368                 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1369                 RecurseAndApply(thread, obj, keyName, receiver, transformType);
1370                 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1371             }
1372         } else {
1373             // Let keys be ? EnumerableOwnPropertyNames(val, key).
1374             JSHandle<TaggedArray> ownerNames(JSObject::EnumerableOwnNames(thread, obj));
1375             RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1376             uint32_t namesLength = ownerNames->GetLength();
1377             JSMutableHandle<JSTaggedValue> keyName(thread, JSTaggedValue::Undefined());
1378             for (uint32_t i = 0; i < namesLength; i++) {
1379                 keyName.Update(ownerNames->Get(thread, i));
1380                 RecurseAndApply(thread, obj, keyName, receiver, transformType);
1381                 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1382             }
1383         }
1384     }
1385 
1386     // Return ? Call(receiver, holder, « name, val »).
1387     const uint32_t argsLength = 2;  // 2: « name, val »
1388     JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
1389     EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, receiver, objHandle, undefined, argsLength);
1390     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1391     info->SetCallArg(name.GetTaggedValue(), val.GetTaggedValue());
1392     JSTaggedValue result = JSFunction::Call(info);
1393     RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread);
1394     return JSHandle<JSTaggedValue>(thread, result);
1395 }
1396 
RecurseAndApply(JSThread * thread,const JSHandle<JSObject> & holder,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & receiver,TransformType transformType)1397 bool Internalize::RecurseAndApply(JSThread *thread, const JSHandle<JSObject> &holder,
1398                                   const JSHandle<JSTaggedValue> &name, const JSHandle<JSTaggedValue> &receiver,
1399                                   TransformType transformType)
1400 {
1401     STACK_LIMIT_CHECK(thread, false);
1402     JSHandle<JSTaggedValue> value = InternalizeJsonProperty(thread, holder, name, receiver, transformType);
1403     bool changeResult = false;
1404 
1405     // If newElement is undefined, then Perform ? val.[[Delete]](P).
1406     if (value->IsUndefined()) {
1407         SCheckMode sCheckMode = transformType == TransformType::SENDABLE ? SCheckMode::SKIP : SCheckMode::CHECK;
1408         changeResult = JSTaggedValue::DeleteProperty(thread, JSHandle<JSTaggedValue>(holder), name, sCheckMode);
1409         RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false);
1410     } else {
1411         // Perform ? CreateDataProperty(val, P, newElement)
1412         changeResult = JSObject::CreateDataProperty(thread, holder, name, value);
1413     }
1414     return changeResult;
1415 }
1416 }  // namespace panda::ecmascript::base
1417