• 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 
20 namespace panda::ecmascript::base {
21 
22 template<typename T>
Launch(Text begin,Text end)23 JSHandle<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 
54 template<typename T>
ParseJSONText()55 JSTaggedValue 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 
280 template<typename T>
CreateJsonArray(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & elementsList)281 JSHandle<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 
293 template<typename T>
CreateSJsonArray(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & elementsList)294 JSHandle<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 
307 template<typename T>
CreateJsonObject(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & propertyList)308 JSHandle<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 
328 template<typename T>
CreateSJsonObject(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & propertyList)329 JSHandle<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 
409 template<typename T>
CreateSharedMap()410 JSHandle<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 
426 template<typename T>
CreateMap()427 JSHandle<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 
437 template<typename T>
CreateJsonMap(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & propertyList)438 JSHandle<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 
455 template<typename T>
CreateSJsonMap(JsonContinuation continuation,std::vector<JSHandle<JSTaggedValue>> & propertyList)456 JSHandle<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 
489 template<typename T>
SetPropertyByValue(const JSHandle<JSTaggedValue> & receiver,const JSHandle<JSTaggedValue> & key,const JSHandle<JSTaggedValue> & value)490 JSTaggedValue 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 
511 template<typename T>
ParseNumber(bool inObjorArr)512 JSTaggedValue 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 
555 template<typename T>
ConvertToNumber(const std::string & str,bool negative,bool hasExponent,bool hasDecimal)556 JSTaggedValue 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 
594 template<typename T>
ParseStringLength(size_t & length,bool & isAscii,bool inObjOrArrOrMap)595 bool 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 
618 template<typename T>
CheckBackslash(Text & text,Text last,bool & isAscii)619 bool 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 
687 template<typename T>
688 template<typename Char>
ParseBackslash(Char * & p)689 void 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 
746 template<typename T>
747 template<typename Char>
CopyCharWithBackslash(Char * & p)748 void 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 
763 template<typename T>
ParseStringWithBackslash(bool inObjOrArrOrMap)764 JSHandle<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 
792 template<typename T>
SkipEndWhiteSpace()793 void 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 
804 template<typename T>
SkipStartWhiteSpace()805 void 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 
816 template<typename T>
GetNextNonSpaceChar()817 void JsonParser<T>::GetNextNonSpaceChar()
818 {
819     Advance();
820     SkipStartWhiteSpace();
821 }
822 
823 template<typename T>
ParseToken()824 Tokens 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 
856 template<typename T>
ParseLiteralTrue()857 JSTaggedValue 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 
871 template<typename T>
ParseLiteralFalse()872 JSTaggedValue 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 
886 template<typename T>
ParseLiteralNull()887 JSTaggedValue 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 
901 template<typename T>
MatchText(const char * str,uint32_t matchLen)902 bool 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 
914 template<typename T>
ReadNumberRange(bool & isFast,int32_t & fastInteger)915 bool 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 
975 template<typename T>
AdvanceLastNumberCharacter(Text current)976 typename JsonParser<T>::Text JsonParser<T>::AdvanceLastNumberCharacter(Text current)
977 {
978     return std::find_if(current, range_, [this](T c) { return !IsNumberCharacter(c); });
979 }
980 
981 template<typename T>
IsNumberCharacter(T ch)982 bool JsonParser<T>::IsNumberCharacter(T ch)
983 {
984     if (ch >= '0' && ch <= '9') {
985         return true;
986     }
987     return false;
988 }
989 
990 template<typename T>
IsNumberSignalCharacter(T ch)991 bool JsonParser<T>::IsNumberSignalCharacter(T ch)
992 {
993     return ch == '.' || ch == 'e' || ch == 'E' || ch == '+' || ch == '-';
994 }
995 
996 template<typename T>
IsExponentNumber()997 bool 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 
1013 template<typename T>
IsDecimalsLegal(bool & hasExponent)1014 bool 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 
1040 template<typename T>
IsExponentLegal(bool & hasExponent)1041 bool 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 
1059 template<typename T>
CheckZeroBeginNumber(bool & hasExponent,bool & hasDecimal)1060 bool 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 
1079 template<typename T>
CheckNonZeroBeginNumber(bool & hasExponent,bool & hasDecimal)1080 bool 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 
Parse(const JSHandle<EcmaString> & strHandle)1102 JSHandle<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 
ParticalParseString(std::string & str,Text current,Text nextCurrent)1128 void Utf8JsonParser::ParticalParseString(std::string& str, Text current, Text nextCurrent)
1129 {
1130     str += std::string_view(reinterpret_cast<const char *>(current), nextCurrent - current);
1131 }
1132 
UpdatePointersListener(void * utf8Parser)1133 void 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 
ParseString(bool inObjOrArrOrMap)1148 JSHandle<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 
ReadJsonStringRange(bool & isFastString)1181 bool 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 
IsFastParseJsonString(bool & isFastString)1201 bool 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 
Parse(EcmaString * str)1217 JSHandle<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 
ParticalParseString(std::string & str,Text current,Text nextCurrent)1227 void Utf16JsonParser::ParticalParseString(std::string& str, Text current, Text nextCurrent)
1228 {
1229     str += StringHelper::U16stringToString(std::u16string(current, nextCurrent));
1230 }
1231 
ParseString(bool inObjOrArrOrMap)1232 JSHandle<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 
ReadJsonStringRange(bool & isFastString,bool & isAscii)1278 bool 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 
IsFastParseJsonString(bool & isFastString,bool & isAscii)1298 bool 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 
IsLegalAsciiCharacter(uint16_t c,bool & isAscii)1314 bool 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 
InternalizeJsonProperty(JSThread * thread,const JSHandle<JSObject> & holder,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & receiver,TransformType transformType)1323 JSHandle<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 
RecurseAndApply(JSThread * thread,const JSHandle<JSObject> & holder,const JSHandle<JSTaggedValue> & name,const JSHandle<JSTaggedValue> & receiver,TransformType transformType)1377 bool 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