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