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