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