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