From c7ed414099cbe975ed1a2039d9f543e8ae045ccb Mon Sep 17 00:00:00 2001 From: xujie Date: Fri, 24 Sep 2021 10:36:25 +0800 Subject: [PATCH] optimize json parse Signed-off-by: xujie --- ecmascript/base/json_parser.cpp | 730 +------------------------ ecmascript/base/json_parser.h | 760 ++++++++++++++++++++++++-- ecmascript/builtins/builtins_json.cpp | 13 +- ecmascript/napi/jsnapi.cpp | 12 +- 4 files changed, 759 insertions(+), 756 deletions(-) diff --git a/ecmascript/base/json_parser.cpp b/ecmascript/base/json_parser.cpp index 1702080a9a..ec31ca0f6f 100644 --- a/ecmascript/base/json_parser.cpp +++ b/ecmascript/base/json_parser.cpp @@ -14,739 +14,65 @@ */ #include "ecmascript/base/json_parser.h" -#include "ecmascript/base/builtins_base.h" -#include "ecmascript/base/number_helper.h" -#include "ecmascript/base/string_helper.h" -#include "ecmascript/base/utf_helper.h" -#include "ecmascript/ecma_string-inl.h" -#include "ecmascript/ecma_string.h" -#include "ecmascript/internal_call_params.h" -#include "ecmascript/interpreter/fast_runtime_stub-inl.h" -#include "ecmascript/js_array.h" -#include "ecmascript/js_function.h" -#include "ecmascript/js_handle.h" -#include "ecmascript/js_tagged_value.h" -#include "ecmascript/object_factory.h" namespace panda::ecmascript::base { -constexpr unsigned int UNICODE_DIGIT_LENGTH = 4; -constexpr unsigned int NUMBER_TEN = 10; -constexpr unsigned int NUMBER_SIXTEEN = 16; - -constexpr unsigned char CODE_SPACE = 0x20; -constexpr unsigned char ASCII_END = 0X7F; -JSHandle JsonParser::Parse(Text begin, Text end) -{ - end_ = end - 1; - current_ = begin; - - auto vm = thread_->GetEcmaVM(); - factory_ = vm->GetFactory(); - env_ = *vm->GetGlobalEnv(); - - SkipEndWhiteSpace(); - range_ = end_; - JSTaggedValue result = ParseJSONText(); - return JSHandle(thread_, result); -} - -JSHandle JsonParser::Parse(EcmaString *str) -{ - ASSERT(str != nullptr); - if (UNLIKELY(str->IsUtf16())) { - uint32_t len = str->GetLength(); - std::u16string u16str = StringHelper::Utf16ToU16String(str->GetDataUtf16(), len); - std::string u8str = StringHelper::U16stringToString(u16str); - Text begin = reinterpret_cast(u8str.c_str()); - return Parse(begin, begin + u8str.length()); - } - - isAsciiString_ = true; - CVector buf(str->GetUtf8Length()); - str->CopyDataUtf8(buf.data(), str->GetUtf8Length()); - Text begin = buf.data(); - return Parse(begin, begin + str->GetLength()); -} - -template -JSTaggedValue JsonParser::ParseJSONText() -{ - SkipStartWhiteSpace(); - Tokens token = ParseToken(); - switch (token) { - case Tokens::OBJECT: - return ParseObject(); - case Tokens::ARRAY: - return ParseArray(); - case Tokens::LITERAL_TRUE: - return ParseLiteral("true", Tokens::LITERAL_TRUE); - case Tokens::LITERAL_FALSE: - return ParseLiteral("false", Tokens::LITERAL_FALSE); - case Tokens::LITERAL_NULL: - return ParseLiteral("null", Tokens::LITERAL_NULL); - case Tokens::NUMBER: - return ParseNumber(); - case Tokens::STRING: - return ParseString(); - default: - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); - } -} - -JsonParser::Tokens JsonParser::ParseToken() -{ - switch (*current_) { - case '{': - return Tokens::OBJECT; - case '[': - return Tokens::ARRAY; - case '"': - return Tokens::STRING; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '-': - return Tokens::NUMBER; - case 't': - return Tokens::LITERAL_TRUE; - case 'f': - return Tokens::LITERAL_FALSE; - case 'n': - return Tokens::LITERAL_NULL; - default: - return Tokens::TOKEN_ILLEGAL; - } -} - -void JsonParser::SkipEndWhiteSpace() -{ - while (current_ != end_) { - if (*end_ == ' ' || *end_ == '\r' || *end_ == '\n' || *end_ == '\t') { - end_--; - } else { - break; - } - } -} - -void JsonParser::SkipStartWhiteSpace() -{ - while (current_ != end_) { - if (*current_ == ' ' || *current_ == '\r' || *current_ == '\n' || *current_ == '\t') { - current_++; - } else { - break; - } - } -} - -void JsonParser::GetNextNonSpaceChar() -{ - current_++; - SkipStartWhiteSpace(); -} - -JSTaggedValue JsonParser::ParseLiteral(CString str, Tokens literalToken) -{ - uint32_t strLen = str.size() - 1; - uint32_t remainingLength = range_ - current_; - if (UNLIKELY(remainingLength < strLen)) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); - } - - bool isMatch = MatchText(str, strLen); - if (LIKELY(isMatch)) { - switch (literalToken) { - case Tokens::LITERAL_TRUE: - return JSTaggedValue::True(); - case Tokens::LITERAL_FALSE: - return JSTaggedValue::False(); - case Tokens::LITERAL_NULL: - return JSTaggedValue::Null(); - default: - UNREACHABLE(); - } - } - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); -} - -bool JsonParser::MatchText(CString str, uint32_t matchLen) -{ - const char *text = str.c_str(); - uint32_t pos = 1; - while (pos <= matchLen) { - if (current_[pos] != text[pos]) { - return false; - } - pos++; - } - current_ += matchLen; - return true; -} - -template -JSTaggedValue JsonParser::ParseNumber() -{ - if (inObjOrArr) { - bool isFast = true; - bool isNumber = ReadNumberRange(isFast); - if (!isNumber) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); - } - if (isFast) { - double result = NumberHelper::StringToDouble(current_, end_ + 1, 0, 0); - current_ = end_; - return JSTaggedValue(result); - } - } - - Text current = current_; - bool hasExponent = false; - if (*current_ == '-') { - if (UNLIKELY(current_++ == end_)) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); - } - } - if (*current_ == '0') { - if (!CheckZeroBeginNumber(hasExponent)) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); - } - } else if (*current_ >= '1' && *current_ <= '9') { - if (!CheckNonZeroBeginNumber(hasExponent)) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); - } - } else { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); - } - - double result = NumberHelper::StringToDouble(current, end_ + 1, 0, 0); - current_ = end_; - return JSTaggedValue(result); -} - -bool JsonParser::CheckZeroBeginNumber(bool &hasExponent) -{ - if (current_++ != end_) { - if (*current_ == '.') { - if (!IsDecimalsLegal(hasExponent)) { - return false; - } - } else if (*current_ == 'e' || *current_ == 'E') { - if (!IsExponentLegal(hasExponent)) { - return false; - } - } else { - return false; - } - } - return true; -} - -bool JsonParser::CheckNonZeroBeginNumber(bool &hasExponent) -{ - while (current_ != end_) { - current_++; - if (IsNumberCharacter(*current_)) { - continue; - } else if (*current_ == '.') { - if (!IsDecimalsLegal(hasExponent)) { - return false; - } - } else if (*current_ == 'e' || *current_ == 'E') { - if (!IsExponentLegal(hasExponent)) { - return false; - } - } else { - return false; - } - } - return true; -} - -bool JsonParser::ReadNumberRange(bool &isFast) -{ - Text current = current_; - if (*current == '0') { - isFast = false; - current++; - } else if (*current == '-') { - current++; - if (*current == '0') { - isFast = false; - current++; - } - } - - while (current != range_) { - if (IsNumberCharacter(*current)) { - current++; - continue; - } else if (IsNumberSignalCharacter(*current)) { - isFast = false; - current++; - continue; - } else { - Text end = current; - while (current != range_) { - if (*current == ' ' || *current == '\r' || *current == '\n' || *current == '\t') { - current++; - } else if (*current == ',' || *current == ']' || *current == '}') { - end_ = end - 1; - return true; - } else { - return false; - } - } - return false; - } - } - end_ = range_ - 1; - return true; -} - -bool JsonParser::IsNumberCharacter(uint8_t ch) -{ - if (ch >= '0' && ch <= '9') { - return true; - } - return false; -} - -bool JsonParser::IsNumberSignalCharacter(uint8_t ch) -{ - return ch == '.' || ch == 'e' || ch == 'E' || ch == '+' || ch == '-'; -} - -bool JsonParser::IsExponentNumber() -{ - if (IsNumberCharacter(*current_)) { - return true; - } else if (*current_ == '-' || *current_ == '+') { - if (current_ == end_) { - return false; - } - current_++; - if (IsNumberCharacter(*current_)) { - return true; - } - } - return false; -} - -bool JsonParser::IsDecimalsLegal(bool &hasExponent) -{ - if (current_ == end_ && !IsNumberCharacter(*++current_)) { - return false; - } - - while (current_ != end_) { - current_++; - if (IsNumberCharacter(*current_)) { - continue; - } else if (*current_ == 'e' || *current_ == 'E') { - if (hasExponent || current_ == end_) { - return false; - } - current_++; - if (!IsExponentNumber()) { - return false; - } - hasExponent = true; - } else { - return false; - } - } - return true; -} - -bool JsonParser::IsExponentLegal(bool &hasExponent) -{ - if (hasExponent || current_ == end_) { - return false; - } - current_++; - if (!IsExponentNumber()) { - return false; - } - while (current_ != end_) { - if (!IsNumberCharacter(*current_)) { - return false; - } - current_++; - } - return true; -} - -bool JsonParser::ReadStringRange(bool &isFast, bool &isAscii) -{ - uint8_t c = 0; - Text current = current_; - - while (current != range_) { - c = *current; - if (c == '"') { - end_ = current; - return true; - } else if (UNLIKELY(c == '\\')) { - if (*(current + 1) == '"') { - current++; - } - isFast = false; - } - if (!IsLegalAsciiCharacter(c, isAscii)) { - return false; - } - current++; - } - return false; -} - -bool JsonParser::ReadAsciiStringRange(bool &isFast) -{ - uint8_t c = 0; - Text current = current_; - - while (current != range_) { - c = *current; - if (c == '"') { - end_ = current; - return true; - } else if (UNLIKELY(c == '\\')) { - if (*(current + 1) == '"') { - current++; - } - isFast = false; - } else if (UNLIKELY(c < CODE_SPACE)) { - return false; - } - current++; - } - return false; -} - -inline bool JsonParser::IsLegalAsciiCharacter(uint8_t c, bool &isAscii) -{ - if (c <= ASCII_END) { - if (c >= CODE_SPACE) { - return true; - } - return false; - } - isAscii = false; - return true; -} - -template -JSTaggedValue JsonParser::ParseString() -{ - bool isFast = true; - bool isAscii = true; - bool isLegal = true; - if (inObjorArr) { - current_++; - if (isAsciiString_) { - isLegal = ReadAsciiStringRange(isFast); - } else { - isLegal = ReadStringRange(isFast, isAscii); - } - if (!isLegal) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception()); - } - if (isFast) { - CString value(current_, end_); - current_ = end_; - if (isAscii) { - return factory_->NewFromUtf8LiteralUnCheck(reinterpret_cast(value.c_str()), value.length(), true) - .GetTaggedValue(); - } - return factory_->NewFromUtf8LiteralUnCheck(reinterpret_cast(value.c_str()), value.length(), false) - .GetTaggedValue(); - } - } else { - if (*end_ != '"' || current_ == end_) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception()); - } - current_++; - if (isAsciiString_) { - isLegal = IsFastParseString(isFast, isAscii); - } else { - isLegal = IsFastParseAsciiString(isFast); - } - if (!isLegal) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception()); - } - if (LIKELY(isFast)) { - CString value(current_, end_); - if (isAscii) { - return factory_->NewFromUtf8LiteralUnCheck(reinterpret_cast(value.c_str()), value.length(), true) - .GetTaggedValue(); - } - return factory_->NewFromUtf8LiteralUnCheck(reinterpret_cast(value.c_str()), value.length(), false) - .GetTaggedValue(); - } - } - end_--; - CString res; - while (current_ <= end_) { - if (*current_ == '\\') { - if (current_ == end_) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); - } - current_++; - switch (*current_) { - case '\"': - res += "\""; - break; - case '\\': - res += "\\"; - break; - case '/': - res += "/"; - break; - case 'b': - res += "\b"; - break; - case 'f': - res += "\f"; - break; - case 'n': - res += "\n"; - break; - case 'r': - res += "\r"; - break; - case 't': - res += "\t"; - break; - case 'u': { - CVector vec; - if (UNLIKELY(!ConvertStringUnicode(vec))) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); - } - std::u16string u16Str; - u16Str.assign(vec.begin(), vec.end()); - res += base::StringHelper::U16stringToString(u16Str); - break; - } - default: - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); - } - } else { - res += *current_; - } - current_++; - } - return factory_->NewFromUtf8Literal(reinterpret_cast(res.c_str()), res.length()).GetTaggedValue(); -} - -bool JsonParser::IsFastParseString(bool &isFast, bool &isAscii) -{ - Text current = current_; - while (current != end_) { - if (!IsLegalAsciiCharacter(*current, isAscii)) { - return false; - } - if (*current == '\\') { - isFast = false; - } - current++; - } - return true; -} - -bool JsonParser::IsFastParseAsciiString(bool &isFast) -{ - Text current = current_; - while (current != end_) { - if (*current < CODE_SPACE) { - return false; - } else if (*current == '\\') { - isFast = false; - } - current++; - } - return true; -} - -bool JsonParser::ConvertStringUnicode(CVector &vec) -{ - uint32_t remainingLength = end_ - current_; - if (remainingLength < UNICODE_DIGIT_LENGTH) { - return false; - } - uint16_t res = 0; - uint32_t exponent = UNICODE_DIGIT_LENGTH; - for (uint32_t pos = 0; pos < UNICODE_DIGIT_LENGTH; pos++) { - current_++; - exponent--; - if (*current_ >= '0' && *current_ <= '9') { - res += (*current_ - '0') * pow(NUMBER_SIXTEEN, exponent); - } else if (*current_ >= 'a' && *current_ <= 'f') { - res += (*current_ - 'a' + NUMBER_TEN) * pow(NUMBER_SIXTEEN, exponent); - } else if (*current_ >= 'A' && *current_ <= 'F') { - res += (*current_ - 'A' + NUMBER_TEN) * pow(NUMBER_SIXTEEN, exponent); - } else { - return false; - } - } - if (res < CODE_SPACE) { - return false; - } - - vec.emplace_back(res); - - if (*(current_ + 1) == '\\' && *(current_ + 2) == 'u') { // 2: next two chars - current_ += 2; // 2: point moves backwards by two digits - return ConvertStringUnicode(vec); - } - return true; -} - -template -JSTaggedValue JsonParser::ParseArray() -{ - if (UNLIKELY(*range_ != ']' && !inObjorArr)) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception()); - } - - current_++; - JSHandle arr = factory_->NewJSArray(); - if (*current_ == ']') { - return arr.GetTaggedValue(); - } - - JSTaggedValue value; - uint32_t index = 0; - while (current_ <= range_) { - value = ParseJSONText(); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); - FastRuntimeStub::SetPropertyByIndex(thread_, arr.GetTaggedValue(), index++, value); - GetNextNonSpaceChar(); - if (*current_ == ',') { - current_++; - } else if (*current_ == ']') { - if (inObjorArr || current_ == range_) { - return arr.GetTaggedValue(); - } else { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception()); - } - } - } - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception()); -} - -template -JSTaggedValue JsonParser::ParseObject() -{ - if (UNLIKELY(*range_ != '}' && !inObjorArr)) { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); - } - - JSHandle proto = env_->GetObjectFunction(); - JSHandle result = factory_->NewJSObjectByConstructor(JSHandle(proto), proto); - current_++; - if (*current_ == '}') { - return result.GetTaggedValue(); - } - - JSMutableHandle keyHandle(thread_, JSTaggedValue::Undefined()); - JSTaggedValue value; - while (current_ <= range_) { - SkipStartWhiteSpace(); - if (*current_ == '"') { - keyHandle.Update(ParseString()); - } else { - if (*current_ == '}' && (inObjorArr || current_ == range_)) { - return result.GetTaggedValue(); - } - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); - } - GetNextNonSpaceChar(); - if (*current_ == ':') { - current_++; - } else { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); - } - value = ParseJSONText(); - FastRuntimeStub::SetPropertyByValue(thread_, result.GetTaggedValue(), keyHandle.GetTaggedValue(), value); - GetNextNonSpaceChar(); - if (*current_ == ',') { - current_++; - } else if (*current_ == '}') { - if (inObjorArr || current_ == range_) { - return result.GetTaggedValue(); - } else { - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); - } - } - } - THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); -} - -JSHandle JsonParser::InternalizeJsonProperty(const JSHandle &holder, - const JSHandle &name, - const JSHandle &receiver) +JSHandle Internalize::InternalizeJsonProperty(JSThread *thread, const JSHandle &holder, + const JSHandle &name, + const JSHandle &receiver) { JSHandle objHandle(holder); - JSHandle val = JSTaggedValue::GetProperty(thread_, objHandle, name).GetValue(); - JSHandle lengthKey = thread_->GlobalConstants()->GetHandledLengthString(); + JSHandle val = JSTaggedValue::GetProperty(thread, objHandle, name).GetValue(); + JSHandle lengthKey = thread->GlobalConstants()->GetHandledLengthString(); if (val->IsECMAObject()) { - JSHandle obj = JSTaggedValue::ToObject(thread_, val); - bool isArray = val->IsArray(thread_); + JSHandle obj = JSTaggedValue::ToObject(thread, val); + bool isArray = val->IsArray(thread); if (isArray) { - JSHandle lenResult = JSTaggedValue::GetProperty(thread_, val, lengthKey).GetValue(); - RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_); - JSTaggedNumber lenNumber = JSTaggedValue::ToLength(thread_, lenResult); - RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_); + JSHandle lenResult = JSTaggedValue::GetProperty(thread, val, lengthKey).GetValue(); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); + JSTaggedNumber lenNumber = JSTaggedValue::ToLength(thread, lenResult); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); array_size_t length = lenNumber.ToUint32(); - JSMutableHandle keyUnknow(thread_, JSTaggedValue::Undefined()); - JSMutableHandle keyName(thread_, JSTaggedValue::Undefined()); + JSMutableHandle keyUnknow(thread, JSTaggedValue::Undefined()); + JSMutableHandle keyName(thread, JSTaggedValue::Undefined()); for (array_size_t i = 0; i < length; i++) { // Let prop be ! ToString((I)). keyUnknow.Update(JSTaggedValue(i)); - keyName.Update(JSTaggedValue::ToString(thread_, keyUnknow).GetTaggedValue()); - RecurseAndApply(obj, keyName, receiver); + keyName.Update(JSTaggedValue::ToString(thread, keyUnknow).GetTaggedValue()); + RecurseAndApply(thread, obj, keyName, receiver); } } else { // Let keys be ? EnumerableOwnPropertyNames(val, key). - JSHandle ownerNames(JSObject::EnumerableOwnNames(thread_, obj)); - RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread_); + JSHandle ownerNames(JSObject::EnumerableOwnNames(thread, obj)); + RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); array_size_t namesLength = ownerNames->GetLength(); - JSMutableHandle keyName(thread_, JSTaggedValue::Undefined()); + JSMutableHandle keyName(thread, JSTaggedValue::Undefined()); for (array_size_t i = 0; i < namesLength; i++) { - keyName.Update(JSTaggedValue::GetProperty(thread_, JSHandle(ownerNames), i) + keyName.Update(JSTaggedValue::GetProperty(thread, JSHandle(ownerNames), i) .GetValue().GetTaggedValue()); - RecurseAndApply(obj, keyName, receiver); + RecurseAndApply(thread, obj, keyName, receiver); } } } // Return ? Call(receiver, holder, « name, val »). - InternalCallParams *arguments = thread_->GetInternalCallParams(); + InternalCallParams *arguments = thread->GetInternalCallParams(); arguments->MakeArgv(name, val); - JSTaggedValue result = JSFunction::Call(thread_, receiver, objHandle, 2, arguments->GetArgv()); // 2: two args - return JSHandle(thread_, result); + JSTaggedValue result = JSFunction::Call(thread, receiver, objHandle, 2, arguments->GetArgv()); // 2: two args + return JSHandle(thread, result); } -bool JsonParser::RecurseAndApply(const JSHandle &holder, const JSHandle &name, - const JSHandle &receiver) +bool Internalize::RecurseAndApply(JSThread *thread, const JSHandle &holder, + const JSHandle &name, const JSHandle &receiver) { - JSHandle value = InternalizeJsonProperty(holder, name, receiver); + JSHandle value = InternalizeJsonProperty(thread, holder, name, receiver); bool changeResult = false; // If newElement is undefined, then Perform ? val.[[Delete]](P). if (value->IsUndefined()) { - changeResult = JSObject::DeleteProperty(thread_, holder, name); + changeResult = JSObject::DeleteProperty(thread, holder, name); } else { // Perform ? CreateDataProperty(val, P, newElement) - changeResult = JSObject::CreateDataProperty(thread_, holder, name, value); + changeResult = JSObject::CreateDataProperty(thread, holder, name, value); } return changeResult; } diff --git a/ecmascript/base/json_parser.h b/ecmascript/base/json_parser.h index c94e5f27d3..82fc2566ac 100644 --- a/ecmascript/base/json_parser.h +++ b/ecmascript/base/json_parser.h @@ -16,27 +16,29 @@ #ifndef ECMASCRIPT_BASE_JSON_PARSE_INL_H #define ECMASCRIPT_BASE_JSON_PARSE_INL_H -#include "ecmascript/js_tagged_value.h" -#include "ecmascript/js_handle.h" +#include "ecmascript/base/json_parser.h" +#include "ecmascript/base/builtins_base.h" +#include "ecmascript/base/number_helper.h" +#include "ecmascript/base/string_helper.h" +#include "ecmascript/base/utf_helper.h" +#include "ecmascript/ecma_string-inl.h" +#include "ecmascript/ecma_string.h" +#include "ecmascript/internal_call_params.h" +#include "ecmascript/interpreter/fast_runtime_stub-inl.h" +#include "ecmascript/js_array.h" #include "ecmascript/js_function.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/object_factory.h" namespace panda::ecmascript::base { -class JsonParser { -public: - using Text = const uint8_t *; - explicit JsonParser() = default; - explicit JsonParser(JSThread *thread) : thread_(thread) {} - ~JsonParser() = default; - NO_COPY_SEMANTIC(JsonParser); - NO_MOVE_SEMANTIC(JsonParser); - JSHandle Parse(Text begin, Text end); - JSHandle Parse(EcmaString *str); - JSHandle InternalizeJsonProperty(const JSHandle &holder, - const JSHandle &name, - const JSHandle &receiver); +constexpr unsigned int UNICODE_DIGIT_LENGTH = 4; +constexpr unsigned int NUMBER_TEN = 10; +constexpr unsigned int NUMBER_SIXTEEN = 16; -private: - enum class Tokens : uint8_t { +constexpr unsigned char CODE_SPACE = 0x20; +constexpr unsigned char ASCII_END = 0X7F; +enum class Tokens : uint8_t { // six structural tokens OBJECT = 0, ARRAY, @@ -48,45 +50,699 @@ private: TOKEN_ILLEGAL, }; +template +class JsonParser { +public: + using Text = const T *; + explicit JsonParser() = default; + explicit JsonParser(JSThread *thread) : thread_(thread) {} + ~JsonParser() = default; + NO_COPY_SEMANTIC(JsonParser); + NO_MOVE_SEMANTIC(JsonParser); + JSHandle Parse(Text begin, Text end) + { + end_ = end - 1; + current_ = begin; + + auto vm = thread_->GetEcmaVM(); + factory_ = vm->GetFactory(); + env_ = *vm->GetGlobalEnv(); + + SkipEndWhiteSpace(); + range_ = end_; + JSTaggedValue result = ParseJSONText(); + return JSHandle(thread_, result); + } + + JSHandle ParseUtf8(EcmaString *str) + { + ASSERT(str != nullptr); + isAsciiString_ = true; + uint32_t len = str->GetUtf8Length(); + CVector buf(len); + str->CopyDataUtf8(buf.data(), len); + Text begin = buf.data(); + return Parse(begin, begin + str->GetLength()); + } + + JSHandle ParseUtf16(EcmaString *str) + { + ASSERT(str != nullptr); + uint32_t len = str->GetLength(); + CVector buf(len); + str->CopyDataUtf16(buf.data(), len); + Text begin = buf.data(); + return Parse(begin, begin + len); + } + +private: template - JSTaggedValue ParseJSONText(); + JSTaggedValue ParseJSONText() + { + SkipStartWhiteSpace(); + Tokens token = ParseToken(); + switch (token) { + case Tokens::OBJECT: + return ParseObject(); + case Tokens::ARRAY: + return ParseArray(); + case Tokens::LITERAL_TRUE: + return ParseLiteral("true", Tokens::LITERAL_TRUE); + case Tokens::LITERAL_FALSE: + return ParseLiteral("false", Tokens::LITERAL_FALSE); + case Tokens::LITERAL_NULL: + return ParseLiteral("null", Tokens::LITERAL_NULL); + case Tokens::NUMBER: + return ParseNumber(); + case Tokens::STRING: + return ParseString(); + default: + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); + } + } template - JSTaggedValue ParseNumber(); + JSTaggedValue ParseNumber() + { + if (inObjOrArr) { + bool isFast = true; + bool isNumber = ReadNumberRange(isFast); + if (!isNumber) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); + } + if (isFast) { + std::string strNum(current_, end_ + 1); + current_ = end_; + return JSTaggedValue(std::stod(strNum)); + } + } + + Text current = current_; + bool hasExponent = false; + if (*current_ == '-') { + if (UNLIKELY(current_++ == end_)) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); + } + } + if (*current_ == '0') { + if (!CheckZeroBeginNumber(hasExponent)) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); + } + } else if (*current_ >= '1' && *current_ <= '9') { + if (!CheckNonZeroBeginNumber(hasExponent)) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); + } + } else { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Number in JSON", JSTaggedValue::Exception()); + } + + std::string strNum(current, end_ + 1); + current_ = end_; + return JSTaggedValue(std::stod(strNum)); + } + + bool ReadJsonStringRange(bool &isFastString, bool &isAscii) + { + current_++; + if (isAsciiString_) { + return ReadAsciiStringRange(isFastString); + } + return ReadStringRange(isFastString, isAscii); + } + + bool IsFastParseJsonString(bool &isFastString, bool &isAscii) + { + current_++; + if (isAsciiString_) { + return IsFastParseString(isFastString, isAscii); + } + return IsFastParseAsciiString(isFastString); + } + + bool ParseBackslash(CString &res) + { + if (current_ == end_) { + return false; + } + current_++; + switch (*current_) { + case '\"': + res += "\""; + break; + case '\\': + res += "\\"; + break; + case '/': + res += "/"; + break; + case 'b': + res += "\b"; + break; + case 'f': + res += "\f"; + break; + case 'n': + res += "\n"; + break; + case 'r': + res += "\r"; + break; + case 't': + res += "\t"; + break; + case 'u': { + CVector vec; + if (UNLIKELY(!ConvertStringUnicode(vec))) { + return false; + } + std::u16string u16Str; + u16Str.assign(vec.begin(), vec.end()); + res += base::StringHelper::U16stringToString(u16Str); + break; + } + default: + return false; + } + return true; + } + + JSTaggedValue SlowParseString() + { + end_--; + CString res; + while (current_ <= end_) { + if (*current_ == '\\') { + bool isLegalChar = ParseBackslash(res); + if (!isLegalChar) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected string in JSON", JSTaggedValue::Exception()); + } + } else { + res += *current_; + } + current_++; + } + return factory_->NewFromUtf8Literal(reinterpret_cast(res.c_str()), res.length()) + .GetTaggedValue(); + } template - JSTaggedValue ParseString(); + JSTaggedValue ParseString() + { + bool isFastString = true; + bool isAscii = true; + bool isLegal = true; + if (inObjorArr) { + isLegal = ReadJsonStringRange(isFastString, isAscii); + if (!isLegal) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception()); + } + if (isFastString) { + if (isAscii) { + CString value(current_, end_); + current_ = end_; + return factory_->NewFromUtf8LiteralUnCheck( + reinterpret_cast(value.c_str()), value.length(), true).GetTaggedValue(); + } + std::u16string value(current_, end_); + current_ = end_; + return factory_->NewFromUtf16LiteralUnCheck( + reinterpret_cast(value.c_str()), value.length(), false).GetTaggedValue(); + } + } else { + if (*end_ != '"' || current_ == end_) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception()); + } + isLegal = IsFastParseJsonString(isFastString, isAscii); + if (!isLegal) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected end Text in JSON", JSTaggedValue::Exception()); + } + if (LIKELY(isFastString)) { + if (isAscii) { + CString value(current_, end_); + return factory_->NewFromUtf8LiteralUnCheck( + reinterpret_cast(value.c_str()), value.length(), true).GetTaggedValue(); + } + std::u16string value(current_, end_); + return factory_->NewFromUtf16LiteralUnCheck( + reinterpret_cast(value.c_str()), value.length(), false).GetTaggedValue(); + } + } + return SlowParseString(); + } template - JSTaggedValue ParseArray(); + JSTaggedValue ParseArray() + { + if (UNLIKELY(*range_ != ']' && !inObjorArr)) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception()); + } + + current_++; + JSHandle arr = factory_->NewJSArray(); + if (*current_ == ']') { + return arr.GetTaggedValue(); + } + + JSTaggedValue value; + uint32_t index = 0; + while (current_ <= range_) { + value = ParseJSONText(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); + FastRuntimeStub::SetPropertyByIndex(thread_, arr.GetTaggedValue(), index++, value); + GetNextNonSpaceChar(); + if (*current_ == ',') { + current_++; + } else if (*current_ == ']') { + if (inObjorArr || current_ == range_) { + return arr.GetTaggedValue(); + } else { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception()); + } + } + } + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Array in JSON", JSTaggedValue::Exception()); + } template - JSTaggedValue ParseObject(); - - void SkipEndWhiteSpace(); - void SkipStartWhiteSpace(); - void GetNextNonSpaceChar(); - JsonParser::Tokens ParseToken(); - JSTaggedValue ParseLiteral(CString str, Tokens literalToken); - bool MatchText(CString str, uint32_t matchLen); - bool ReadNumberRange(bool &isFast); - bool IsNumberCharacter(uint8_t ch); - bool IsNumberSignalCharacter(uint8_t ch); - bool IsExponentNumber(); - bool IsDecimalsLegal(bool &hasExponent); - bool IsExponentLegal(bool &hasExponent); - bool ReadStringRange(bool &isFast, bool &isAscii); - bool ReadAsciiStringRange(bool &isFast); - bool IsFastParseString(bool &isFast, bool &isAscii); - bool IsFastParseAsciiString(bool &isFast); - bool ConvertStringUnicode(CVector &vec); - bool CheckZeroBeginNumber(bool &hasExponent); - bool CheckNonZeroBeginNumber(bool &hasExponent); - - bool RecurseAndApply(const JSHandle &holder, const JSHandle &name, - const JSHandle &receiver); - - inline bool IsLegalAsciiCharacter(uint8_t c, bool &isAscii); + JSTaggedValue ParseObject() + { + if (UNLIKELY(*range_ != '}' && !inObjorArr)) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); + } + + JSHandle proto = env_->GetObjectFunction(); + JSHandle result = factory_->NewJSObjectByConstructor(JSHandle(proto), proto); + current_++; + if (*current_ == '}') { + return result.GetTaggedValue(); + } + + JSMutableHandle keyHandle(thread_, JSTaggedValue::Undefined()); + JSTaggedValue value; + while (current_ <= range_) { + SkipStartWhiteSpace(); + if (*current_ == '"') { + keyHandle.Update(ParseString()); + } else { + if (*current_ == '}' && (inObjorArr || current_ == range_)) { + return result.GetTaggedValue(); + } + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); + } + GetNextNonSpaceChar(); + if (*current_ == ':') { + current_++; + } else { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); + } + value = ParseJSONText(); + FastRuntimeStub::SetPropertyByValue( + thread_, result.GetTaggedValue(), keyHandle.GetTaggedValue(), value); + GetNextNonSpaceChar(); + if (*current_ == ',') { + current_++; + } else if (*current_ == '}') { + if (inObjorArr || current_ == range_) { + return result.GetTaggedValue(); + } else { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); + } + } + } + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); + } + + void SkipEndWhiteSpace() + { + while (current_ != end_) { + if (*end_ == ' ' || *end_ == '\r' || *end_ == '\n' || *end_ == '\t') { + end_--; + } else { + break; + } + } + } + + void SkipStartWhiteSpace() + { + while (current_ != end_) { + if (*current_ == ' ' || *current_ == '\r' || *current_ == '\n' || *current_ == '\t') { + current_++; + } else { + break; + } + } + } + + void GetNextNonSpaceChar() + { + current_++; + SkipStartWhiteSpace(); + } + + Tokens ParseToken() + { + switch (*current_) { + case '{': + return Tokens::OBJECT; + case '[': + return Tokens::ARRAY; + case '"': + return Tokens::STRING; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return Tokens::NUMBER; + case 't': + return Tokens::LITERAL_TRUE; + case 'f': + return Tokens::LITERAL_FALSE; + case 'n': + return Tokens::LITERAL_NULL; + default: + return Tokens::TOKEN_ILLEGAL; + } + } + + JSTaggedValue ParseLiteral(CString str, Tokens literalToken) + { + uint32_t strLen = str.size() - 1; + uint32_t remainingLength = range_ - current_; + if (UNLIKELY(remainingLength < strLen)) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); + } + + bool isMatch = MatchText(str, strLen); + if (LIKELY(isMatch)) { + switch (literalToken) { + case Tokens::LITERAL_TRUE: + return JSTaggedValue::True(); + case Tokens::LITERAL_FALSE: + return JSTaggedValue::False(); + case Tokens::LITERAL_NULL: + return JSTaggedValue::Null(); + default: + UNREACHABLE(); + } + } + THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Text in JSON", JSTaggedValue::Exception()); + } + + bool MatchText(CString str, uint32_t matchLen) + { + const char *text = str.c_str(); + uint32_t pos = 1; + while (pos <= matchLen) { + if (current_[pos] != text[pos]) { + return false; + } + pos++; + } + current_ += matchLen; + return true; + } + + bool ReadNumberRange(bool &isFast) + { + Text current = current_; + if (*current == '0') { + isFast = false; + current++; + } else if (*current == '-') { + current++; + if (*current == '0') { + isFast = false; + current++; + } + } + + while (current != range_) { + if (IsNumberCharacter(*current)) { + current++; + continue; + } else if (IsNumberSignalCharacter(*current)) { + isFast = false; + current++; + continue; + } + Text end = current; + while (current != range_) { + if (*current == ' ' || *current == '\r' || *current == '\n' || *current == '\t') { + current++; + } else if (*current == ',' || *current == ']' || *current == '}') { + end_ = end - 1; + return true; + } else { + return false; + } + } + return false; + } + end_ = range_ - 1; + return true; + } + + bool IsNumberCharacter(T ch) + { + if (ch >= '0' && ch <= '9') { + return true; + } + return false; + } + + bool IsNumberSignalCharacter(T ch) + { + return ch == '.' || ch == 'e' || ch == 'E' || ch == '+' || ch == '-'; + } + + bool IsExponentNumber() + { + if (IsNumberCharacter(*current_)) { + return true; + } else if (*current_ == '-' || *current_ == '+') { + if (current_ == end_) { + return false; + } + current_++; + if (IsNumberCharacter(*current_)) { + return true; + } + } + return false; + } + + bool IsDecimalsLegal(bool &hasExponent) + { + if (current_ == end_ && !IsNumberCharacter(*++current_)) { + return false; + } + + while (current_ != end_) { + current_++; + if (IsNumberCharacter(*current_)) { + continue; + } else if (*current_ == 'e' || *current_ == 'E') { + if (hasExponent || current_ == end_) { + return false; + } + current_++; + if (!IsExponentNumber()) { + return false; + } + hasExponent = true; + } else { + return false; + } + } + return true; + } + + bool IsExponentLegal(bool &hasExponent) + { + if (hasExponent || current_ == end_) { + return false; + } + current_++; + if (!IsExponentNumber()) { + return false; + } + while (current_ != end_) { + if (!IsNumberCharacter(*current_)) { + return false; + } + current_++; + } + return true; + } + + bool ReadStringRange(bool &isFast, bool &isAscii) + { + T c = 0; + Text current = current_; + + while (current != range_) { + c = *current; + if (c == '"') { + end_ = current; + return true; + } else if (UNLIKELY(c == '\\')) { + if (*(current + 1) == '"') { + current++; + } + isFast = false; + } + if (!IsLegalAsciiCharacter(c, isAscii)) { + return false; + } + current++; + } + return false; + } + + bool ReadAsciiStringRange(bool &isFast) + { + T c = 0; + Text current = current_; + + while (current != range_) { + c = *current; + if (c == '"') { + end_ = current; + return true; + } else if (UNLIKELY(c == '\\')) { + if (*(current + 1) == '"') { + current++; + } + isFast = false; + } else if (UNLIKELY(c < CODE_SPACE)) { + return false; + } + current++; + } + return false; + } + + bool IsFastParseString(bool &isFast, bool &isAscii) + { + Text current = current_; + while (current != end_) { + if (!IsLegalAsciiCharacter(*current, isAscii)) { + return false; + } + if (*current == '\\') { + isFast = false; + } + current++; + } + return true; + } + + bool IsFastParseAsciiString(bool &isFast) + { + Text current = current_; + while (current != end_) { + if (*current < CODE_SPACE) { + return false; + } else if (*current == '\\') { + isFast = false; + } + current++; + } + return true; + } + + bool ConvertStringUnicode(CVector &vec) + { + uint32_t remainingLength = end_ - current_; + if (remainingLength < UNICODE_DIGIT_LENGTH) { + return false; + } + uint16_t res = 0; + uint32_t exponent = UNICODE_DIGIT_LENGTH; + for (uint32_t pos = 0; pos < UNICODE_DIGIT_LENGTH; pos++) { + current_++; + exponent--; + if (*current_ >= '0' && *current_ <= '9') { + res += (*current_ - '0') * pow(NUMBER_SIXTEEN, exponent); + } else if (*current_ >= 'a' && *current_ <= 'f') { + res += (*current_ - 'a' + NUMBER_TEN) * pow(NUMBER_SIXTEEN, exponent); + } else if (*current_ >= 'A' && *current_ <= 'F') { + res += (*current_ - 'A' + NUMBER_TEN) * pow(NUMBER_SIXTEEN, exponent); + } else { + return false; + } + } + if (res < CODE_SPACE) { + return false; + } + + vec.emplace_back(res); + + if (*(current_ + 1) == '\\' && *(current_ + 2) == 'u') { // 2: next two chars + current_ += 2; // 2: point moves backwards by two digits + return ConvertStringUnicode(vec); + } + return true; + } + + bool CheckZeroBeginNumber(bool &hasExponent) + { + if (current_++ != end_) { + if (*current_ == '.') { + if (!IsDecimalsLegal(hasExponent)) { + return false; + } + } else if (*current_ == 'e' || *current_ == 'E') { + if (!IsExponentLegal(hasExponent)) { + return false; + } + } else { + return false; + } + } + return true; + } + + bool CheckNonZeroBeginNumber(bool &hasExponent) + { + while (current_ != end_) { + current_++; + if (IsNumberCharacter(*current_)) { + continue; + } else if (*current_ == '.') { + if (!IsDecimalsLegal(hasExponent)) { + return false; + } + } else if (*current_ == 'e' || *current_ == 'E') { + if (!IsExponentLegal(hasExponent)) { + return false; + } + } else { + return false; + } + } + return true; + } + + bool IsLegalAsciiCharacter(T c, bool &isAscii) + { + if (c <= ASCII_END) { + if (c >= CODE_SPACE) { + return true; + } + return false; + } + isAscii = false; + return true; + } bool isAsciiString_{false}; Text end_{nullptr}; @@ -96,6 +752,16 @@ private: ObjectFactory *factory_{nullptr}; GlobalEnv *env_{nullptr}; }; + +class Internalize { +public: + static JSHandle InternalizeJsonProperty(JSThread *thread, const JSHandle &holder, + const JSHandle &name, + const JSHandle &receiver); +private: + static bool RecurseAndApply(JSThread *thread, const JSHandle &holder, const JSHandle &name, + const JSHandle &receiver); +}; } // namespace panda::ecmascript::base #endif // ECMASCRIPT_BASE_JSON_PARSE_INL_H diff --git a/ecmascript/builtins/builtins_json.cpp b/ecmascript/builtins/builtins_json.cpp index 692da8075e..703581abe1 100644 --- a/ecmascript/builtins/builtins_json.cpp +++ b/ecmascript/builtins/builtins_json.cpp @@ -44,9 +44,14 @@ JSTaggedValue BuiltinsJson::Parse(EcmaRuntimeCallInfo *argv) JSHandle msg = GetCallArg(argv, 0); JSHandle parseString = JSTaggedValue::ToString(thread, msg); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - - panda::ecmascript::base::JsonParser parser(thread); - JSHandle result = parser.Parse(*parseString); + JSHandle result; + if (parseString->IsUtf8()) { + panda::ecmascript::base::JsonParser parser(thread); + result = parser.ParseUtf8(*parseString); + } else { + panda::ecmascript::base::JsonParser parser(thread); + result = parser.ParseUtf16(*parseString); + } RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue reviver = JSTaggedValue::Undefined(); @@ -63,7 +68,7 @@ JSTaggedValue BuiltinsJson::Parse(EcmaRuntimeCallInfo *argv) // Perform ! CreateDataPropertyOrThrow(root, rootName, unfiltered). bool success = JSObject::CreateDataProperty(thread, root, rootName, result); if (success) { - result = parser.InternalizeJsonProperty(root, rootName, callbackfnHandle); + result = base::Internalize::InternalizeJsonProperty(thread, root, rootName, callbackfnHandle); } } } diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index ff7223a2c1..a583f026f6 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -1174,9 +1174,15 @@ EXCEPTION_ERROR_ALL(EXCEPTION_ERROR_NEW) Local JSON::Parse(const EcmaVM *vm, Local string) { JSThread *thread = vm->GetJSThread(); - JsonParser parser(thread); - JSHandle result = - parser.Parse(EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject())); + auto ecmaStr = EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject()); + JSHandle result; + if (ecmaStr->IsUtf8()) { + JsonParser parser(thread); + result = parser.ParseUtf8(EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject())); + } else { + JsonParser parser(thread); + result = parser.ParseUtf16(EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject())); + } RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(result); } -- Gitee