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