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