From 69613ba0b5528d95ec058bd771b196ddededd264 Mon Sep 17 00:00:00 2001 From: chenkeyu Date: Sat, 7 Jun 2025 20:41:06 +0800 Subject: [PATCH] add json stringify fastpath Signed-off-by: chenkeyu --- .../plugins/ets/runtime/CMakeLists.txt | 2 + .../ets/runtime/ets_libbase_runtime.yaml | 14 + .../ets/runtime/ets_panda_file_items.h | 2 + .../ets/runtime/ets_platform_types.cpp | 4 + .../plugins/ets/runtime/ets_platform_types.h | 4 + .../ets/runtime/intrinsics/escompat_JSON.cpp | 33 ++ .../intrinsics/helpers/json_helper.cpp | 361 ++++++++++++++++++ .../runtime/intrinsics/helpers/json_helper.h | 63 +++ .../plugins/ets/stdlib/escompat/json.ets | 11 +- static_core/plugins/ets/subproject_sources.gn | 2 + static_core/runtime/include/class.h | 10 + 11 files changed, 505 insertions(+), 1 deletion(-) create mode 100644 static_core/plugins/ets/runtime/intrinsics/escompat_JSON.cpp create mode 100644 static_core/plugins/ets/runtime/intrinsics/helpers/json_helper.cpp create mode 100644 static_core/plugins/ets/runtime/intrinsics/helpers/json_helper.h diff --git a/static_core/plugins/ets/runtime/CMakeLists.txt b/static_core/plugins/ets/runtime/CMakeLists.txt index b915c5b670..fcab0ebf91 100644 --- a/static_core/plugins/ets/runtime/CMakeLists.txt +++ b/static_core/plugins/ets/runtime/CMakeLists.txt @@ -38,6 +38,7 @@ set(ETS_RUNTIME_SOURCES ${ETS_EXT_SOURCES}/intrinsics/escompat_ArrayBuffer.cpp ${ETS_EXT_SOURCES}/intrinsics/escompat_TypedArrays.cpp ${ETS_EXT_SOURCES}/intrinsics/escompat_Date.cpp + ${ETS_EXT_SOURCES}/intrinsics/escompat_JSON.cpp ${ETS_EXT_SOURCES}/intrinsics/escompat_RegExp.cpp ${ETS_EXT_SOURCES}/intrinsics/escompat_taskpool.cpp ${ETS_EXT_SOURCES}/intrinsics/escompat_Reflect.cpp @@ -79,6 +80,7 @@ set(ETS_RUNTIME_SOURCES ${ETS_EXT_SOURCES}/intrinsics/helpers/array_buffer_helper.cpp ${ETS_EXT_SOURCES}/intrinsics/helpers/ets_intrinsics_helpers.cpp ${ETS_EXT_SOURCES}/intrinsics/helpers/ets_to_string_cache.cpp + ${ETS_EXT_SOURCES}/intrinsics/helpers/json_helper.cpp ${ETS_EXT_SOURCES}/finalreg/finalization_registry_manager.cpp ${ETS_EXT_SOURCES}/unhandled_manager/unhandled_object_manager.cpp ${ETS_EXT_SOURCES}/mem/ets_reference_processor.cpp diff --git a/static_core/plugins/ets/runtime/ets_libbase_runtime.yaml b/static_core/plugins/ets/runtime/ets_libbase_runtime.yaml index 54cc602be5..d0c385f008 100644 --- a/static_core/plugins/ets/runtime/ets_libbase_runtime.yaml +++ b/static_core/plugins/ets/runtime/ets_libbase_runtime.yaml @@ -651,6 +651,20 @@ intrinsics: args: [ std.core.String ] impl: ark::ets::intrinsics::LoadLibrary +################### +# Escompat.JSON # +################### + + - name: EscompatJSONStringifyFast + space: ets + class_name: escompat.JSON + method_name: stringifyFast + static: true + signature: + ret: std.core.String + args: [ std.core.Object ] + impl: ark::ets::intrinsics::EscompatJSONStringifyFast + ################### # std.core.String # ################### diff --git a/static_core/plugins/ets/runtime/ets_panda_file_items.h b/static_core/plugins/ets/runtime/ets_panda_file_items.h index 4bf9ab0ff1..7f10ca0051 100644 --- a/static_core/plugins/ets/runtime/ets_panda_file_items.h +++ b/static_core/plugins/ets/runtime/ets_panda_file_items.h @@ -201,6 +201,8 @@ static constexpr std::string_view ES_ERROR = "Lstd/i static constexpr std::string_view ARRAY = "Lescompat/Array;"; static constexpr std::string_view ARRAY_AS_LIST_INT = "Lstd/containers/ArrayAsListInt;"; +static constexpr std::string_view REG_EXP_EXEC_ARRAY = "Lescompat/RegExpExecArray;"; +static constexpr std::string_view JSON_REPLACER = "Lescompat/JsonReplacer;"; // ANI annotation classes static constexpr std::string_view ANI_UNSAFE_QUICK = "Lstd/annotations/ani/unsafe/Quick;"; diff --git a/static_core/plugins/ets/runtime/ets_platform_types.cpp b/static_core/plugins/ets/runtime/ets_platform_types.cpp index f488200132..9c116393d1 100644 --- a/static_core/plugins/ets/runtime/ets_platform_types.cpp +++ b/static_core/plugins/ets/runtime/ets_platform_types.cpp @@ -191,6 +191,10 @@ EtsPlatformTypes::EtsPlatformTypes([[maybe_unused]] EtsCoroutine *coro) "Lescompat/Array;:V", true); findMethod(&EtsPlatformTypes::escompatProcessListUnhandledPromises, escompatProcess, "listUnhandledPromises", "Lescompat/Array;:V", true); + + findType(&EtsPlatformTypes::coreTuple, TUPLE); + findType(&EtsPlatformTypes::escompatRegExpExecArray, REG_EXP_EXEC_ARRAY); + findType(&EtsPlatformTypes::escompatJsonReplacer, JSON_REPLACER); } } // namespace ark::ets diff --git a/static_core/plugins/ets/runtime/ets_platform_types.h b/static_core/plugins/ets/runtime/ets_platform_types.h index e0ab701915..0c0aa58508 100644 --- a/static_core/plugins/ets/runtime/ets_platform_types.h +++ b/static_core/plugins/ets/runtime/ets_platform_types.h @@ -109,6 +109,10 @@ public: EtsMethod *escompatProcessListUnhandledJobs {}; EtsMethod *escompatProcessListUnhandledPromises {}; + EtsClass *coreTuple {}; + EtsClass *escompatRegExpExecArray {}; + EtsClass *escompatJsonReplacer {}; + struct Entry { size_t slotIndex {}; }; diff --git a/static_core/plugins/ets/runtime/intrinsics/escompat_JSON.cpp b/static_core/plugins/ets/runtime/intrinsics/escompat_JSON.cpp new file mode 100644 index 0000000000..b87831d7ce --- /dev/null +++ b/static_core/plugins/ets/runtime/intrinsics/escompat_JSON.cpp @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "types/ets_string.h" +#include "helpers/json_helper.h" + +namespace ark::ets::intrinsics { + +extern "C" EtsString *EscompatJSONStringifyFast(EtsObject *value) +{ + auto coro = EtsCoroutine::GetCurrent(); + ASSERT(coro->HasPendingException() == false); + + EtsHandleScope scope(coro); + EtsHandle valueHandle(coro, value); + + helpers::JSONStringifier stringifier; + return stringifier.Stringify(valueHandle); +} + +} // namespace ark::ets::intrinsics diff --git a/static_core/plugins/ets/runtime/intrinsics/helpers/json_helper.cpp b/static_core/plugins/ets/runtime/intrinsics/helpers/json_helper.cpp new file mode 100644 index 0000000000..0c702fd5be --- /dev/null +++ b/static_core/plugins/ets/runtime/intrinsics/helpers/json_helper.cpp @@ -0,0 +1,361 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ets_exceptions.h" +#include "ets_handle.h" +#include "types/ets_escompat_array.h" +#include "types/ets_object.h" +#include "json_helper.h" +#include "ets_to_string_cache.h" +namespace ark::ets::intrinsics::helpers { + +void JSONStringifier::AppendJSONString(EtsHandle &value, bool hasContent) +{ + if (hasContent) { + buffer_ += ","; + } + buffer_ += "\""; + buffer_ += key_; + buffer_ += "\":"; + SerializeObject(value); +} + +void JSONStringifier::AppendJSONPrimitive(const PandaString &value, bool hasContent) +{ + if (hasContent) { + buffer_ += ","; + } + + buffer_ += "\""; + buffer_ += key_; + buffer_ += "\":"; + + if ((value == "NaN") || (value == "Infinity") || (value == "-Infinity")) { + buffer_ += "null"; + } else { + buffer_ += value; + } +} + +void JSONStringifier::SerializeFields(EtsHandle &value) +{ + bool hasContent = false; + + value->GetClass()->EnumerateBaseClasses([&](EtsClass *c) { + auto fields = c->GetRuntimeClass()->GetRawFirstFieldAddr(); + auto fnum = c->GetRuntimeClass()->GetNumFields(); + for (uint32_t i = 0; i < fnum; i++) { + HandleField(value, EtsField::FromRuntimeField(&fields[i]), hasContent); + } + return false; + }); +} + +void JSONStringifier::SerializeJSONObject(EtsHandle &value) +{ + bool isContain = PushValue(value); + if (isContain) { + ThrowEtsException(EtsCoroutine::GetCurrent(), panda_file_items::class_descriptors::TYPE_ERROR, + "cyclic object value"); + return; + } + buffer_ += "{"; + SerializeFields(value); + buffer_ += "}"; +} + +void JSONStringifier::SerializeJSONArray(EtsHandle &value) +{ + auto coro = EtsCoroutine::GetCurrent(); + + buffer_ += "["; + auto array = EtsObjectArray::FromEtsObject(value.GetPtr()); + auto length = array->GetLength(); + + for (size_t i = 0; i < length; ++i) { + EtsHandle elem; + elem = EtsHandle(coro, array->Get(i)); + if (elem->GetClass()->IsFunction()) { + buffer_ += "null"; + } else { + SerializeObject(elem); + } + if (i != length - 1) { + buffer_ += ","; + } + } + + buffer_ += "]"; +} + +void JSONStringifier::SerializeJSONString(EtsHandle &value) +{ + buffer_ += "\""; + buffer_ += EtsString::FromEtsObject(value.GetPtr())->GetMutf8(); + buffer_ += "\""; +} + +void JSONStringifier::SerializeJSONBoxedBoolean(EtsHandle &value) +{ + auto val = EtsBoxPrimitive::FromCoreType(value.GetPtr())->GetValue(); + if (val == true) { + buffer_ += "true"; + } else { + buffer_ += "false"; + } +} + +void JSONStringifier::SerializeJSONBoxedDouble(EtsHandle &value) +{ + auto val = EtsBoxPrimitive::FromCoreType(value.GetPtr())->GetValue(); + auto cache = PandaEtsVM::GetCurrent()->GetDoubleToStringCache(); + buffer_ += cache->GetOrCache(EtsCoroutine::GetCurrent(), val)->GetMutf8(); +} +void JSONStringifier::SerializeJSONBoxedFloat(EtsHandle &value) +{ + auto val = EtsBoxPrimitive::FromCoreType(value.GetPtr())->GetValue(); + auto cache = PandaEtsVM::GetCurrent()->GetFloatToStringCache(); + buffer_ += cache->GetOrCache(EtsCoroutine::GetCurrent(), val)->GetMutf8(); +} + +void JSONStringifier::SerializeJSONBoxedLong(EtsHandle &value) +{ + auto val = EtsBoxPrimitive::FromCoreType(value.GetPtr())->GetValue(); + auto cache = PandaEtsVM::GetCurrent()->GetLongToStringCache(); + buffer_ += cache->GetOrCache(EtsCoroutine::GetCurrent(), val)->GetMutf8(); +} + +template +void JSONStringifier::SerializeJSONBoxedPrimitiveNoCache(EtsHandle &value) +{ + T val = EtsBoxPrimitive::FromCoreType(value.GetPtr())->GetValue(); + buffer_ += std::to_string(val); +} + +void JSONStringifier::SerializeEmptyObject() +{ + buffer_ += "{}"; +} + +void JSONStringifier::SerializeJSONNullValue() +{ + buffer_ += "null"; +} + +void JSONStringifier::SerializeJSONRecord(EtsHandle &value) +{ + buffer_ += "{"; + auto cls = value->GetClass(); + auto headEntry = cls->GetFieldByIndex(3); + auto coro = EtsCoroutine::GetCurrent(); + + EtsHandleScope scope(coro); + EtsHandle head(coro, value->GetFieldObject(headEntry)); + + auto hasContent = false; + EtsHandle next(coro, head->GetFieldObject(head->GetClass()->GetFieldByIndex(1))); + do { + EtsHandle key(coro, next->GetFieldObject(next->GetClass()->GetFieldByIndex(2))); + EtsHandle val(coro, next->GetFieldObject(next->GetClass()->GetFieldByIndex(3))); + + next = EtsHandle(coro, next->GetFieldObject(next->GetClass()->GetFieldByIndex(1))); + + if (val.GetPtr() == nullptr) { + continue; + } + + if (val->GetClass()->IsFunction()) { + continue; + } + + if (key->IsStringClass()) { + key_ = EtsString::FromEtsObject(key.GetPtr())->GetMutf8(); + } else { + auto intVal = EtsBoxPrimitive::FromCoreType(key.GetPtr())->GetValue(); + key_ = std::to_string(intVal); + } + AppendJSONString(val, hasContent); + hasContent = true; + + } while (head.GetPtr() != next.GetPtr() && next.GetPtr() != nullptr); + buffer_ += "}"; +} + +bool JSONStringifier::PushValue(EtsHandle &value) +{ + if (path_.find(value->GetHashCode()) != path_.end()) { + return true; + } + path_.insert(value->GetHashCode()); + return false; +} + +PandaString JSONStringifier::ResolveDisplayName(const EtsField *field) +{ + auto fieldNameData = field->GetCoreType()->GetName(); + auto fieldNameLength = fieldNameData.utf16Length; + std::string_view fieldName(utf::Mutf8AsCString(fieldNameData.data), fieldNameLength); + if (fieldName.rfind(PROPERTY, 0) == 0) { + ASSERT(fieldNameLength > PROPERTY_PREFIX_LENGTH); + return PandaString(reinterpret_cast( + fieldNameData.data + // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + PROPERTY_PREFIX_LENGTH), + fieldNameLength - PROPERTY_PREFIX_LENGTH); + } + return PandaString(reinterpret_cast(fieldNameData.data), fieldNameLength); +} + +void JSONStringifier::SerializeObject(EtsHandle &value) +{ + if (value.GetPtr() == nullptr) { + return; + } + + auto coro = EtsCoroutine::GetCurrent(); + auto platformTypes = PlatformTypes(coro); + + auto desc = value->GetClass()->GetDescriptor(); + if (desc == panda_file_items::class_descriptors::BOX_BOOLEAN) { + SerializeJSONBoxedBoolean(value); + } else if (desc == panda_file_items::class_descriptors::BOX_DOUBLE) { + SerializeJSONBoxedDouble(value); + } else if (desc == panda_file_items::class_descriptors::BOX_FLOAT) { + SerializeJSONBoxedFloat(value); + } else if (desc == panda_file_items::class_descriptors::BOX_LONG) { + SerializeJSONBoxedLong(value); + } else if (desc == panda_file_items::class_descriptors::BOX_BYTE) { + SerializeJSONBoxedPrimitiveNoCache(value); + } else if (desc == panda_file_items::class_descriptors::BOX_SHORT) { + SerializeJSONBoxedPrimitiveNoCache(value); + } else if (desc == panda_file_items::class_descriptors::BOX_CHAR) { + SerializeJSONBoxedPrimitiveNoCache(value); + } else if (desc == panda_file_items::class_descriptors::BOX_INT) { + SerializeJSONBoxedPrimitiveNoCache(value); + } else if (desc == panda_file_items::class_descriptors::STRING) { + SerializeJSONString(value); + } else if (desc == panda_file_items::class_descriptors::ARRAY) { + auto realArray = + EtsHandle(coro, EtsArrayObject::FromEtsObject(value.GetPtr())->GetData()->AsObject()); + SerializeJSONArray(realArray); + } else if (desc == panda_file_items::class_descriptors::PROMISE || + desc == panda_file_items::class_descriptors::SET || desc == panda_file_items::class_descriptors::MAP || + desc == panda_file_items::class_descriptors::MAPENTRY) { + SerializeEmptyObject(); + } else if (desc == panda_file_items::class_descriptors::NULL_VALUE) { + SerializeJSONNullValue(); + } else if (desc == panda_file_items::class_descriptors::JS_VALUE) { + ThrowEtsException(coro, panda_file_items::class_descriptors::TYPE_ERROR, "unsupported tuple"); + } else { + if (value->IsInstanceOf(platformTypes->escompatRegExpExecArray)) { + auto result = EtsHandle(coro, value->GetFieldObject(value->GetClass()->GetFieldByIndex(1))); + auto realArray = EtsHandle( + coro, EtsArrayObject::FromEtsObject(value.GetPtr())->GetData()->AsObject()); + SerializeJSONArray(realArray); + } else if (value->IsInstanceOf(platformTypes->escompatJsonReplacer)) { + PandaVector args {Value(value->GetCoreType())}; + auto jsonReplacerMethod = value->GetClass()->GetInstanceMethod("jsonReplacer", nullptr)->GetPandaMethod(); + auto ret = jsonReplacerMethod->Invoke(coro, args.data()); + if (UNLIKELY(coro->HasPendingException())) { + return; + } + auto retobj = EtsHandle(coro, EtsObject::FromCoreType(ret.GetAs())); + SerializeJSONRecord(retobj); + } else if (value->IsArrayClass()) { + SerializeJSONArray(value); + } else if (value->GetClass()->IsFunction()) { + buffer_ += "undefined"; + } else if (value->IsInstanceOf(platformTypes->coreTuple)) { + ThrowEtsException(coro, panda_file_items::class_descriptors::TYPE_ERROR, "unsupported tuple"); + } else { + SerializeJSONObject(value); + } + } +} + +void JSONStringifier::HandleField(EtsHandle &obj, EtsField *etsField, bool &hasContent) +{ + if (etsField->IsStatic()) { + return; + } + key_ = ResolveDisplayName(etsField); + auto etsType = etsField->GetEtsType(); + + // { BOOLEAN, BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, OBJECT, UNKNOWN, VOID }; + switch (etsType) { + case EtsType::BOOLEAN: { + auto val = obj->GetFieldPrimitive(etsField); + PandaString value = val ? "true" : "false"; + AppendJSONPrimitive(value, hasContent); + break; + } + case EtsType::BYTE: { + auto val = obj->GetFieldPrimitive(etsField); + AppendJSONPrimitive(PandaString(std::to_string(val)), hasContent); + break; + } + case EtsType::CHAR: { + auto val = obj->GetFieldPrimitive(etsField); + AppendJSONPrimitive(PandaString(std::to_string(val)), hasContent); + break; + } + case EtsType::SHORT: { + auto val = obj->GetFieldPrimitive(etsField); + AppendJSONPrimitive(PandaString(std::to_string(val)), hasContent); + break; + } + case EtsType::INT: { + auto val = obj->GetFieldPrimitive(etsField); + AppendJSONPrimitive(PandaString(std::to_string(val)), hasContent); + break; + } + case EtsType::LONG: { + auto val = obj->GetFieldPrimitive(etsField); + auto cache = PandaEtsVM::GetCurrent()->GetLongToStringCache(); + auto strval = cache->GetOrCache(EtsCoroutine::GetCurrent(), val)->GetMutf8(); + AppendJSONPrimitive(strval, hasContent); + break; + } + case EtsType::FLOAT: { + auto val = obj->GetFieldPrimitive(etsField); + auto cache = PandaEtsVM::GetCurrent()->GetFloatToStringCache(); + auto strval = cache->GetOrCache(EtsCoroutine::GetCurrent(), val)->GetMutf8(); + AppendJSONPrimitive(strval, hasContent); + break; + } + case EtsType::DOUBLE: { + auto val = obj->GetFieldPrimitive(etsField); + auto cache = PandaEtsVM::GetCurrent()->GetDoubleToStringCache(); + auto strval = cache->GetOrCache(EtsCoroutine::GetCurrent(), val)->GetMutf8(); + AppendJSONPrimitive(strval, hasContent); + break; + } + default: + auto fieldObj = EtsHandle(EtsCoroutine::GetCurrent(), obj->GetFieldObject(etsField)); + if (fieldObj.GetPtr() == nullptr || fieldObj->GetClass()->IsFunction()) { + return; + } + AppendJSONString(fieldObj, hasContent); + break; + } + hasContent = true; +} + +EtsString *JSONStringifier::Stringify(EtsHandle &value) +{ + SerializeObject(value); + return EtsString::CreateFromUtf8(buffer_.c_str(), buffer_.length()); +} + +} // namespace ark::ets::intrinsics::helpers diff --git a/static_core/plugins/ets/runtime/intrinsics/helpers/json_helper.h b/static_core/plugins/ets/runtime/intrinsics/helpers/json_helper.h new file mode 100644 index 0000000000..516903fb6c --- /dev/null +++ b/static_core/plugins/ets/runtime/intrinsics/helpers/json_helper.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PANDA_PLUGINS_ETS_RUNTIME_JSON_HELPER +#define PANDA_PLUGINS_ETS_RUNTIME_JSON_HELPER + +#include "types/ets_string.h" + +namespace ark::ets::intrinsics::helpers { +class JSONStringifier { +public: + explicit JSONStringifier() = default; + + EtsString *Stringify(EtsHandle &value); + +private: + void AppendJSONString(EtsHandle &value, bool hasContent); + void AppendJSONPrimitive(const PandaString &value, bool hasContent); + + void SerializeFields(EtsHandle &value); + + // handling of types + void SerializeJSONObject(EtsHandle &value); + void SerializeJSONArray(EtsHandle &value); + void SerializeJSONString(EtsHandle &value); + void SerializeJSONBoxedBoolean(EtsHandle &value); + void SerializeJSONBoxedDouble(EtsHandle &value); + void SerializeJSONBoxedFloat(EtsHandle &value); + void SerializeJSONBoxedLong(EtsHandle &value); + + template + void SerializeJSONBoxedPrimitiveNoCache(EtsHandle &value); + + void SerializeEmptyObject(); + void SerializeJSONNullValue(); + void SerializeJSONRecord(EtsHandle &value); + + bool PushValue(EtsHandle &value); + + PandaString ResolveDisplayName(const EtsField *field); + + void SerializeObject(EtsHandle &value); + void HandleField(EtsHandle &obj, EtsField *field, bool &hasContent); + +private: + PandaString buffer_; + PandaString key_; + PandaUnorderedSet path_; +}; +} // namespace ark::ets::intrinsics::helpers +#endif // PANDA_PLUGINS_ETS_RUNTIME_JSON_HELPER diff --git a/static_core/plugins/ets/stdlib/escompat/json.ets b/static_core/plugins/ets/stdlib/escompat/json.ets index e5f93d3117..6c82ab177e 100644 --- a/static_core/plugins/ets/stdlib/escompat/json.ets +++ b/static_core/plugins/ets/stdlib/escompat/json.ets @@ -220,9 +220,18 @@ export class JSON { * @returns String - JSON representation of Object */ public static stringify(obj: NullishType): String { - return new JSONWriter().write(obj) + if (obj === undefined) { + return "undefined" + } + try { + return JSON.stringifyFast(obj) + } catch (e: TypeError) { + return new JSONWriter().write(obj) + } } + private static native stringifyFast(obj: NullishType): String; + public static stringify(obj: JsonReplacer): String { const record = obj.jsonReplacer(); return JSON.stringify(record); diff --git a/static_core/plugins/ets/subproject_sources.gn b/static_core/plugins/ets/subproject_sources.gn index e49fe513fc..01afa803fa 100644 --- a/static_core/plugins/ets/subproject_sources.gn +++ b/static_core/plugins/ets/subproject_sources.gn @@ -124,6 +124,7 @@ srcs_runtime = [ "runtime/intrinsics/escompat_RegExp.cpp", "runtime/intrinsics/escompat_taskpool.cpp", "runtime/intrinsics/escompat_Reflect.cpp", + "runtime/intrinsics/escompat_JSON.cpp", "runtime/intrinsics/std_core.cpp", "runtime/intrinsics/std_core_Char.cpp", "runtime/intrinsics/std_core_Arrays.cpp", @@ -161,6 +162,7 @@ srcs_runtime = [ "runtime/intrinsics/helpers/array_buffer_helper.cpp", "runtime/intrinsics/helpers/ets_intrinsics_helpers.cpp", "runtime/intrinsics/helpers/ets_to_string_cache.cpp", + "runtime/intrinsics/helpers/json_helper.cpp", "runtime/mem/ets_reference_processor.cpp", "runtime/napi/ets_napi_helpers.cpp", "runtime/napi/ets_napi_invoke_interface.cpp", diff --git a/static_core/runtime/include/class.h b/static_core/runtime/include/class.h index a6121da597..d3381150ca 100644 --- a/static_core/runtime/include/class.h +++ b/static_core/runtime/include/class.h @@ -212,6 +212,16 @@ public: return {fields_, numFields_}; } + Field *GetRawFirstFieldAddr() const + { + return fields_; + } + + uint32_t GetNumFields() const + { + return numFields_; + } + Span GetStaticFields() const { return {fields_, numSfields_}; -- Gitee