/*
 * Copyright (c) 2021 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 "ecmascript/accessor_data.h"
#include "ecmascript/class_info_extractor.h"
#include "ecmascript/jspandafile/program_object-inl.h"
#include "ecmascript/ecma_module.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_dictionary-inl.h"
#include "ecmascript/global_env.h"
#include "ecmascript/hprof/heap_profiler.h"
#include "ecmascript/hprof/heap_profiler_interface.h"
#include "ecmascript/hprof/heap_snapshot.h"
#include "ecmascript/hprof/heap_snapshot_json_serializer.h"
#include "ecmascript/hprof/string_hashmap.h"
#include "ecmascript/ic/ic_handler.h"
#include "ecmascript/ic/property_box.h"
#include "ecmascript/ic/proto_change_details.h"
#include "ecmascript/jobs/micro_job_queue.h"
#include "ecmascript/jobs/pending_job.h"
#include "ecmascript/js_api_tree_map.h"
#include "ecmascript/js_api_tree_map_iterator.h"
#include "ecmascript/js_api_tree_set.h"
#include "ecmascript/js_api_tree_set_iterator.h"
#include "ecmascript/js_arguments.h"
#include "ecmascript/js_array.h"
#include "ecmascript/js_api_arraylist.h"
#include "ecmascript/js_api_arraylist_iterator.h"
#include "ecmascript/js_array_iterator.h"
#include "ecmascript/js_arraybuffer.h"
#include "ecmascript/js_async_function.h"
#include "ecmascript/js_bigint.h"
#include "ecmascript/js_collator.h"
#include "ecmascript/js_dataview.h"
#include "ecmascript/js_date.h"
#include "ecmascript/js_date_time_format.h"
#include "ecmascript/js_for_in_iterator.h"
#include "ecmascript/js_function.h"
#include "ecmascript/js_generator_object.h"
#include "ecmascript/js_global_object.h"
#include "ecmascript/js_handle.h"
#include "ecmascript/js_intl.h"
#include "ecmascript/js_locale.h"
#include "ecmascript/js_map.h"
#include "ecmascript/js_map_iterator.h"
#include "ecmascript/js_number_format.h"
#include "ecmascript/js_object-inl.h"
#include "ecmascript/js_plural_rules.h"
#include "ecmascript/js_primitive_ref.h"
#include "ecmascript/js_promise.h"
#include "ecmascript/js_realm.h"
#include "ecmascript/js_regexp.h"
#include "ecmascript/js_relative_time_format.h"
#include "ecmascript/js_set.h"
#include "ecmascript/js_set_iterator.h"
#include "ecmascript/js_string_iterator.h"
#include "ecmascript/js_tagged_number.h"
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/js_typed_array.h"
#include "ecmascript/js_weak_container.h"
#include "ecmascript/layout_info-inl.h"
#include "ecmascript/lexical_env.h"
#include "ecmascript/linked_hash_table-inl.h"
#include "ecmascript/mem/assert_scope-inl.h"
#include "ecmascript/mem/c_containers.h"
#include "ecmascript/mem/machine_code.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/tagged_array.h"
#include "ecmascript/tagged_dictionary.h"
#include "ecmascript/tagged_tree-inl.h"
#include "ecmascript/template_map.h"
#include "ecmascript/tests/test_helper.h"
#include "ecmascript/transitions_dictionary.h"
#include "ecmascript/ts_types/ts_type.h"

using namespace panda::ecmascript;
using namespace panda::ecmascript::base;

namespace panda::test {
class EcmaDumpTest : public testing::Test {
public:
    static void SetUpTestCase()
    {
        GTEST_LOG_(INFO) << "SetUpTestCase";
    }

    static void TearDownTestCase()
    {
        GTEST_LOG_(INFO) << "TearDownCase";
    }

    void SetUp() override
    {
        TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
    }

    void TearDown() override
    {
        TestHelper::DestroyEcmaVMWithScope(instance, scope);
    }

    PandaVM *instance {nullptr};
    ecmascript::EcmaHandleScope *scope {nullptr};
    JSThread *thread {nullptr};
};

#ifndef NDEBUG
HWTEST_F_L0(EcmaDumpTest, Dump)
{
    JSTaggedValue value1(100);
    value1.D();

    JSTaggedValue value2(100.0);
    JSTaggedValue::DV(value2.GetRawData());

    JSTaggedValue::Undefined().D();
    JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
    env.Dump();

    JSHandle<JSFunction> objFunc(env->GetObjectFunction());
    objFunc.Dump();
}
#endif  // #ifndef NDEBUG

static JSHandle<JSMap> NewJSMap(JSThread *thread, ObjectFactory *factory, JSHandle<JSTaggedValue> proto)
{
    JSHandle<JSHClass> mapClass = factory->NewEcmaDynClass(JSMap::SIZE, JSType::JS_MAP, proto);
    JSHandle<JSMap> jsMap = JSHandle<JSMap>::Cast(factory->NewJSObject(mapClass));
    JSHandle<LinkedHashMap> linkedMap(LinkedHashMap::Create(thread));
    jsMap->SetLinkedMap(thread, linkedMap);
    return jsMap;
}

static JSHandle<JSSet> NewJSSet(JSThread *thread, ObjectFactory *factory, JSHandle<JSTaggedValue> proto)
{
    JSHandle<JSHClass> setClass = factory->NewEcmaDynClass(JSSet::SIZE, JSType::JS_SET, proto);
    JSHandle<JSSet> jsSet = JSHandle<JSSet>::Cast(factory->NewJSObject(setClass));
    JSHandle<LinkedHashSet> linkedSet(LinkedHashSet::Create(thread));
    jsSet->SetLinkedSet(thread, linkedSet);
    return jsSet;
}

static JSHandle<JSAPITreeMap> NewJSAPITreeMap(JSThread *thread, ObjectFactory *factory)
{
    auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
    JSHandle<JSTaggedValue> proto = globalEnv->GetObjectFunctionPrototype();
    JSHandle<JSHClass> mapClass = factory->NewEcmaDynClass(JSAPITreeMap::SIZE, JSType::JS_API_TREE_MAP, proto);
    JSHandle<JSAPITreeMap> jsTreeMap = JSHandle<JSAPITreeMap>::Cast(factory->NewJSObject(mapClass));
    JSHandle<TaggedTreeMap> treeMap(thread, TaggedTreeMap::Create(thread));
    jsTreeMap->SetTreeMap(thread, treeMap);
    return jsTreeMap;
}

static JSHandle<JSAPITreeSet> NewJSAPITreeSet(JSThread *thread, ObjectFactory *factory)
{
    auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
    JSHandle<JSTaggedValue> proto = globalEnv->GetObjectFunctionPrototype();
    JSHandle<JSHClass> setClass = factory->NewEcmaDynClass(JSAPITreeSet::SIZE, JSType::JS_API_TREE_SET, proto);
    JSHandle<JSAPITreeSet> jsTreeSet = JSHandle<JSAPITreeSet>::Cast(factory->NewJSObject(setClass));
    JSHandle<TaggedTreeSet> treeSet(thread, TaggedTreeSet::Create(thread));
    jsTreeSet->SetTreeSet(thread, treeSet);
    return jsTreeSet;
}

static JSHandle<JSObject> NewJSObject(JSThread *thread, ObjectFactory *factory, JSHandle<GlobalEnv> globalEnv)
{
    JSFunction *jsFunc = globalEnv->GetObjectFunction().GetObject<JSFunction>();
    JSHandle<JSTaggedValue> jsFunc1(thread, jsFunc);
    JSHandle<JSObject> jsObj = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc1), jsFunc1);
    return jsObj;
}

static JSHandle<JSAPIArrayList> NewJSAPIArrayList(JSThread *thread, ObjectFactory *factory,
                                                  JSHandle<JSTaggedValue> proto)
{
    JSHandle<JSHClass> arrayListClass =
        factory->NewEcmaDynClass(JSAPIArrayList::SIZE, JSType::JS_API_ARRAY_LIST, proto);
    JSHandle<JSAPIArrayList> jsArrayList = JSHandle<JSAPIArrayList>::Cast(factory->NewJSObject(arrayListClass));
    jsArrayList->SetLength(thread, JSTaggedValue(0));
    return jsArrayList;
}

HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
{
    [[maybe_unused]] ecmascript::EcmaHandleScope scope(thread);
    auto factory = thread->GetEcmaVM()->GetFactory();
    auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv();
    auto globalConst = const_cast<GlobalEnvConstants *>(thread->GlobalConstants());
    JSHandle<JSTaggedValue> proto = globalEnv->GetFunctionPrototype();
    std::vector<std::pair<CString, JSTaggedValue>> snapshotVector;

#define DUMP_FOR_HANDLE(dumpHandle)                                        \
    dumpHandle.GetTaggedValue().D();                                       \
    dumpHandle.GetTaggedValue().DumpForSnapshot(thread, snapshotVector);

#define NEW_OBJECT_AND_DUMP(ClassName, TypeName)                                       \
    JSHandle<JSHClass> class##ClassName =                                              \
        factory->NewEcmaDynClass(ClassName::SIZE, JSType::TypeName, proto);            \
        JSHandle<JSObject> object##ClassName = factory->NewJSObject(class##ClassName); \
        object##ClassName.GetTaggedValue().D();                                        \
        object##ClassName.GetTaggedValue().DumpForSnapshot(thread, snapshotVector);

    for (JSType type = JSType::JS_OBJECT; type <= JSType::TYPE_LAST; type = JSType(static_cast<int>(type) + 1)) {
        switch (type) {
            case JSType::JS_ERROR:
            case JSType::JS_EVAL_ERROR:
            case JSType::JS_RANGE_ERROR:
            case JSType::JS_TYPE_ERROR:
            case JSType::JS_REFERENCE_ERROR:
            case JSType::JS_URI_ERROR:
            case JSType::JS_SYNTAX_ERROR:
            case JSType::JS_OBJECT: {
                CHECK_DUMP_FILEDS(ECMAObject::SIZE, JSObject::SIZE, 2)
                JSHandle<JSObject> jsObj = NewJSObject(thread, factory, globalEnv);
                DUMP_FOR_HANDLE(jsObj)
                break;
            }
            case JSType::JS_REALM: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSRealm::SIZE, 2)
                JSHandle<JSRealm> jsRealm = factory->NewJSRealm();
                DUMP_FOR_HANDLE(jsRealm)
                break;
            }
            case JSType::JS_FUNCTION_BASE: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSFunctionBase::SIZE, 1)
                break;
            }
            case JSType::JS_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunctionBase::SIZE, JSFunction::SIZE, 7)
                JSHandle<JSTaggedValue> jsFunc = globalEnv->GetFunctionFunction();
                DUMP_FOR_HANDLE(jsFunc)
                break;
            }
            case JSType::JS_PROXY_REVOC_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunction::SIZE, JSProxyRevocFunction::SIZE, 1)
                JSHandle<JSHClass> proxyRevocClass =
                    JSHandle<JSHClass>::Cast(globalEnv->GetProxyRevocFunctionClass());
                JSHandle<JSObject> proxyRevocFunc = factory->NewJSObject(proxyRevocClass);
                DUMP_FOR_HANDLE(proxyRevocFunc)
                break;
            }
            case JSType::JS_PROMISE_REACTIONS_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunction::SIZE, JSPromiseReactionsFunction::SIZE, 2)
                JSHandle<JSHClass> promiseReactClass =
                    JSHandle<JSHClass>::Cast(globalEnv->GetPromiseReactionFunctionClass());
                JSHandle<JSObject> promiseReactFunc = factory->NewJSObject(promiseReactClass);
                DUMP_FOR_HANDLE(promiseReactFunc)
                break;
            }
            case JSType::JS_PROMISE_EXECUTOR_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunction::SIZE, JSPromiseExecutorFunction::SIZE, 1)
                JSHandle<JSHClass> promiseExeClass =
                    JSHandle<JSHClass>::Cast(globalEnv->GetPromiseExecutorFunctionClass());
                JSHandle<JSObject> promiseExeFunc = factory->NewJSObject(promiseExeClass);
                DUMP_FOR_HANDLE(promiseExeFunc)
                break;
            }
            case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunction::SIZE, JSPromiseAllResolveElementFunction::SIZE, 5)
                JSHandle<JSHClass> promiseAllClass =
                    JSHandle<JSHClass>::Cast(globalEnv->GetPromiseAllResolveElementFunctionClass());
                JSHandle<JSObject> promiseAllFunc = factory->NewJSObject(promiseAllClass);
                DUMP_FOR_HANDLE(promiseAllFunc)
                break;
            }
            case JSType::JS_GENERATOR_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunction::SIZE, JSGeneratorFunction::SIZE, 0)
                break;
            }
            case JSType::JS_ASYNC_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunction::SIZE, JSAsyncFunction::SIZE, 0)
                break;
            }
            case JSType::JS_INTL_BOUND_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunction::SIZE, JSIntlBoundFunction::SIZE, 3)
                JSHandle<JSIntlBoundFunction> intlBoundFunc = factory->NewJSIntlBoundFunction();
                DUMP_FOR_HANDLE(intlBoundFunc)
                break;
            }
            case JSType::JS_ASYNC_AWAIT_STATUS_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunction::SIZE, JSAsyncAwaitStatusFunction::SIZE, 1)
                JSHandle<JSAsyncAwaitStatusFunction> asyncAwaitFunc = factory->NewJSAsyncAwaitStatusFunction();
                DUMP_FOR_HANDLE(asyncAwaitFunc)
                break;
            }
            case JSType::JS_BOUND_FUNCTION: {
                CHECK_DUMP_FILEDS(JSFunctionBase::SIZE, JSBoundFunction::SIZE, 3)
                NEW_OBJECT_AND_DUMP(JSBoundFunction, JS_BOUND_FUNCTION)
                break;
            }
            case JSType::JS_REG_EXP: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSRegExp::SIZE, 4)
                NEW_OBJECT_AND_DUMP(JSRegExp, JS_REG_EXP)
                break;
            }
            case JSType::JS_SET: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSSet::SIZE, 1)
                JSHandle<JSSet> jsSet = NewJSSet(thread, factory, proto);
                DUMP_FOR_HANDLE(jsSet)
                break;
            }
            case JSType::JS_MAP: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSMap::SIZE, 1)
                JSHandle<JSMap> jsMap = NewJSMap(thread, factory, proto);
                DUMP_FOR_HANDLE(jsMap)
                break;
            }
            case JSType::JS_WEAK_MAP: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSWeakMap::SIZE, 1)
                JSHandle<JSHClass> weakMapClass = factory->NewEcmaDynClass(JSWeakMap::SIZE, JSType::JS_WEAK_MAP, proto);
                JSHandle<JSWeakMap> jsWeakMap = JSHandle<JSWeakMap>::Cast(factory->NewJSObject(weakMapClass));
                JSHandle<LinkedHashMap> weakLinkedMap(LinkedHashMap::Create(thread));
                jsWeakMap->SetLinkedMap(thread, weakLinkedMap);
                DUMP_FOR_HANDLE(jsWeakMap)
                break;
            }
            case JSType::JS_WEAK_SET: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSWeakSet::SIZE, 1)
                JSHandle<JSHClass> weakSetClass = factory->NewEcmaDynClass(JSWeakSet::SIZE, JSType::JS_WEAK_SET, proto);
                JSHandle<JSWeakSet> jsWeakSet = JSHandle<JSWeakSet>::Cast(factory->NewJSObject(weakSetClass));
                JSHandle<LinkedHashSet> weakLinkedSet(LinkedHashSet::Create(thread));
                jsWeakSet->SetLinkedSet(thread, weakLinkedSet);
                DUMP_FOR_HANDLE(jsWeakSet)
                break;
            }
            case JSType::JS_DATE: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSDate::SIZE, 2)
                JSHandle<JSHClass> dateClass = factory->NewEcmaDynClass(JSDate::SIZE, JSType::JS_DATE, proto);
                JSHandle<JSDate> date = JSHandle<JSDate>::Cast(factory->NewJSObject(dateClass));
                date->SetTimeValue(thread, JSTaggedValue(0.0));
                date->SetLocalOffset(thread, JSTaggedValue(0.0));
                DUMP_FOR_HANDLE(date)
                break;
            }
            case JSType::JS_ITERATOR:
                // JS Iterate is a tool class, so we don't need to check it.
                break;
            case JSType::JS_FORIN_ITERATOR: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSForInIterator::SIZE, 4)
                JSHandle<JSTaggedValue> array(thread, factory->NewJSArray().GetTaggedValue());
                JSHandle<JSForInIterator> forInIter = factory->NewJSForinIterator(array);
                DUMP_FOR_HANDLE(forInIter)
                break;
            }
            case JSType::JS_MAP_ITERATOR: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSMapIterator::SIZE, 2)
                JSHandle<JSMapIterator> jsMapIter =
                    factory->NewJSMapIterator(NewJSMap(thread, factory, proto), IterationKind::KEY);
                DUMP_FOR_HANDLE(jsMapIter)
                break;
            }
            case JSType::JS_SET_ITERATOR: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSSetIterator::SIZE, 2)
                JSHandle<JSSetIterator> jsSetIter =
                    factory->NewJSSetIterator(NewJSSet(thread, factory, proto), IterationKind::KEY);
                DUMP_FOR_HANDLE(jsSetIter)
                break;
            }
            case JSType::JS_ARRAY_ITERATOR: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSArrayIterator::SIZE, 2)
                JSHandle<JSArrayIterator> arrayIter =
                    factory->NewJSArrayIterator(JSHandle<JSObject>::Cast(factory->NewJSArray()), IterationKind::KEY);
                DUMP_FOR_HANDLE(arrayIter)
                break;
            }
            case JSType::JS_STRING_ITERATOR: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSStringIterator::SIZE, 2)
                JSHandle<JSTaggedValue> stringIter = globalEnv->GetStringIterator();
                DUMP_FOR_HANDLE(stringIter)
                break;
            }
            case JSType::JS_INTL: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSIntl::SIZE, 1)
                NEW_OBJECT_AND_DUMP(JSIntl, JS_INTL)
                break;
            }
            case JSType::JS_LOCALE: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSLocale::SIZE, 1)
                NEW_OBJECT_AND_DUMP(JSLocale, JS_LOCALE)
                break;
            }
            case JSType::JS_DATE_TIME_FORMAT: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSDateTimeFormat::SIZE, 9)
                NEW_OBJECT_AND_DUMP(JSDateTimeFormat, JS_DATE_TIME_FORMAT)
                break;
            }
            case JSType::JS_RELATIVE_TIME_FORMAT: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSRelativeTimeFormat::SIZE, 6)
                NEW_OBJECT_AND_DUMP(JSRelativeTimeFormat, JS_RELATIVE_TIME_FORMAT)
                break;
            }
            case JSType::JS_NUMBER_FORMAT: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSNumberFormat::SIZE, 13)
                NEW_OBJECT_AND_DUMP(JSNumberFormat, JS_NUMBER_FORMAT)
                break;
            }
            case JSType::JS_COLLATOR: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSCollator::SIZE, 5)
                NEW_OBJECT_AND_DUMP(JSCollator, JS_COLLATOR)
                break;
            }
            case JSType::JS_PLURAL_RULES: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSPluralRules::SIZE, 10)
                NEW_OBJECT_AND_DUMP(JSPluralRules, JS_PLURAL_RULES)
                break;
            }
            case JSType::JS_ARRAY_BUFFER: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSArrayBuffer::SIZE, 2)
                NEW_OBJECT_AND_DUMP(JSArrayBuffer, JS_ARRAY_BUFFER)
                break;
            }
            case JSType::JS_PROMISE: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSPromise::SIZE, 4)
                NEW_OBJECT_AND_DUMP(JSPromise, JS_PROMISE)
                break;
            }
            case JSType::JS_DATA_VIEW: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSDataView::SIZE, 3)
                NEW_OBJECT_AND_DUMP(JSDataView, JS_DATA_VIEW)
                break;
            }
            case JSType::JS_ARGUMENTS: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSArguments::SIZE, 1)
                NEW_OBJECT_AND_DUMP(JSArguments, JS_ARGUMENTS)
                break;
            }
            case JSType::JS_GENERATOR_OBJECT: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSGeneratorObject::SIZE, 3)
                NEW_OBJECT_AND_DUMP(JSGeneratorObject, JS_GENERATOR_OBJECT)
                break;
            }
            case JSType::JS_ASYNC_FUNC_OBJECT: {
                CHECK_DUMP_FILEDS(JSGeneratorObject::SIZE, JSAsyncFuncObject::SIZE, 1)
                JSHandle<JSAsyncFuncObject> asyncFuncObject = factory->NewJSAsyncFuncObject();
                DUMP_FOR_HANDLE(asyncFuncObject)
                break;
            }
            case JSType::JS_ARRAY: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSArray::SIZE, 1)
                JSHandle<JSArray> jsArray = factory->NewJSArray();
                DUMP_FOR_HANDLE(jsArray)
                break;
            }
            case JSType::JS_TYPED_ARRAY:
            case JSType::JS_INT8_ARRAY:
            case JSType::JS_UINT8_ARRAY:
            case JSType::JS_UINT8_CLAMPED_ARRAY:
            case JSType::JS_INT16_ARRAY:
            case JSType::JS_UINT16_ARRAY:
            case JSType::JS_INT32_ARRAY:
            case JSType::JS_UINT32_ARRAY:
            case JSType::JS_FLOAT32_ARRAY:
            case JSType::JS_FLOAT64_ARRAY: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSTypedArray::SIZE, 5)
                NEW_OBJECT_AND_DUMP(JSTypedArray, JS_TYPED_ARRAY)
                break;
            }
            case JSType::JS_PRIMITIVE_REF: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSPrimitiveRef::SIZE, 1)
                NEW_OBJECT_AND_DUMP(JSPrimitiveRef, JS_PRIMITIVE_REF)
                break;
            }
            case JSType::JS_GLOBAL_OBJECT: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSGlobalObject::SIZE, 0)
                JSHandle<JSTaggedValue> globalObject = globalEnv->GetJSGlobalObject();
                DUMP_FOR_HANDLE(globalObject)
                break;
            }
            case JSType::JS_PROXY: {
                CHECK_DUMP_FILEDS(ECMAObject::SIZE, JSProxy::SIZE, 3)
                JSHandle<JSTaggedValue> emptyObj(thread, NewJSObject(thread, factory, globalEnv).GetTaggedValue());
                JSHandle<JSProxy> proxy = factory->NewJSProxy(emptyObj, emptyObj);
                DUMP_FOR_HANDLE(proxy)
                break;
            }
            case JSType::HCLASS: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), JSHClass::SIZE, 7)
                JSHandle<JSHClass> hclass = factory->NewEcmaDynClass(JSHClass::SIZE, JSType::HCLASS, proto);
                DUMP_FOR_HANDLE(hclass)
                break;
            }
            case JSType::STRING: {
                DUMP_FOR_HANDLE(globalEnv->GetObjectFunction())
                break;
            }
            case JSType::BIGINT: {
                DUMP_FOR_HANDLE(globalEnv->GetBigIntFunction())
                break;
            }
            case JSType::TAGGED_ARRAY: {
                JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(4);
                DUMP_FOR_HANDLE(taggedArray)
                break;
            }
            case JSType::TAGGED_DICTIONARY: {
                JSHandle<TaggedArray> dict = factory->NewDictionaryArray(4);
                DUMP_FOR_HANDLE(dict)
                break;
            }
            case JSType::FREE_OBJECT_WITH_ONE_FIELD:
            case JSType::FREE_OBJECT_WITH_NONE_FIELD:
            case JSType::FREE_OBJECT_WITH_TWO_FIELD:
            {
                break;
            }
            case JSType::JS_NATIVE_POINTER: {
                break;
            }
            case JSType::GLOBAL_ENV: {
                DUMP_FOR_HANDLE(globalEnv)
                break;
            }
            case JSType::ACCESSOR_DATA:
            case JSType::INTERNAL_ACCESSOR: {
                CHECK_DUMP_FILEDS(Record::SIZE, AccessorData::SIZE, 2)
                JSHandle<AccessorData> accessor = factory->NewAccessorData();
                DUMP_FOR_HANDLE(accessor)
                break;
            }
            case JSType::SYMBOL: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), JSSymbol::SIZE, 2)
                JSHandle<JSSymbol> symbol = factory->NewJSSymbol();
                DUMP_FOR_HANDLE(symbol)
                break;
            }
            case JSType::JS_GENERATOR_CONTEXT: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), GeneratorContext::SIZE, 6)
                JSHandle<GeneratorContext> genContext = factory->NewGeneratorContext();
                DUMP_FOR_HANDLE(genContext)
                break;
            }
            case JSType::PROTOTYPE_HANDLER: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), PrototypeHandler::SIZE, 3)
                JSHandle<PrototypeHandler> protoHandler = factory->NewPrototypeHandler();
                DUMP_FOR_HANDLE(protoHandler)
                break;
            }
            case JSType::TRANSITION_HANDLER: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), TransitionHandler::SIZE, 2)
                JSHandle<TransitionHandler> transitionHandler = factory->NewTransitionHandler();
                DUMP_FOR_HANDLE(transitionHandler)
                break;
            }
            case JSType::PROPERTY_BOX: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), PropertyBox::SIZE, 1)
                JSHandle<PropertyBox> PropertyBox = factory->NewPropertyBox(globalEnv->GetEmptyArray());
                DUMP_FOR_HANDLE(PropertyBox)
                break;
            }
            case JSType::PROTO_CHANGE_MARKER: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), ProtoChangeMarker::SIZE, 1)
                JSHandle<ProtoChangeMarker> protoMaker = factory->NewProtoChangeMarker();
                DUMP_FOR_HANDLE(protoMaker)
                break;
            }
            case JSType::PROTOTYPE_INFO: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), ProtoChangeDetails::SIZE, 2)
                JSHandle<ProtoChangeDetails> protoDetails = factory->NewProtoChangeDetails();
                DUMP_FOR_HANDLE(protoDetails)
                break;
            }
            case JSType::TEMPLATE_MAP: {
                JSHandle<JSTaggedValue> templateMap = globalEnv->GetTemplateMap();
                DUMP_FOR_HANDLE(templateMap)
                break;
            }
            case JSType::PROGRAM: {
                CHECK_DUMP_FILEDS(ECMAObject::SIZE, Program::SIZE, 1)
                JSHandle<Program> program = factory->NewProgram();
                DUMP_FOR_HANDLE(program)
                break;
            }
            case JSType::PROMISE_CAPABILITY: {
                CHECK_DUMP_FILEDS(Record::SIZE, PromiseCapability::SIZE, 3)
                JSHandle<PromiseCapability> promiseCapa = factory->NewPromiseCapability();
                DUMP_FOR_HANDLE(promiseCapa)
                break;
            }
            case JSType::PROMISE_RECORD: {
                CHECK_DUMP_FILEDS(Record::SIZE, PromiseRecord::SIZE, 1)
                JSHandle<PromiseRecord> promiseRecord = factory->NewPromiseRecord();
                DUMP_FOR_HANDLE(promiseRecord)
                break;
            }
            case JSType::RESOLVING_FUNCTIONS_RECORD: {
                CHECK_DUMP_FILEDS(Record::SIZE, ResolvingFunctionsRecord::SIZE, 2)
                JSHandle<ResolvingFunctionsRecord> ResolvingFunc = factory->NewResolvingFunctionsRecord();
                DUMP_FOR_HANDLE(ResolvingFunc)
                break;
            }
            case JSType::PROMISE_REACTIONS: {
                CHECK_DUMP_FILEDS(Record::SIZE, PromiseReaction::SIZE, 3)
                JSHandle<PromiseReaction> promiseReact = factory->NewPromiseReaction();
                DUMP_FOR_HANDLE(promiseReact)
                break;
            }
            case JSType::PROMISE_ITERATOR_RECORD: {
                CHECK_DUMP_FILEDS(Record::SIZE, PromiseIteratorRecord::SIZE, 2)
                JSHandle<JSTaggedValue> emptyObj(thread, NewJSObject(thread, factory, globalEnv).GetTaggedValue());
                JSHandle<PromiseIteratorRecord> promiseIter = factory->NewPromiseIteratorRecord(emptyObj, false);
                DUMP_FOR_HANDLE(promiseIter)
                break;
            }
            case JSType::MICRO_JOB_QUEUE: {
                CHECK_DUMP_FILEDS(Record::SIZE, ecmascript::job::MicroJobQueue::SIZE, 2)
                JSHandle<ecmascript::job::MicroJobQueue> microJob = factory->NewMicroJobQueue();
                DUMP_FOR_HANDLE(microJob)
                break;
            }
            case JSType::PENDING_JOB: {
                CHECK_DUMP_FILEDS(Record::SIZE, ecmascript::job::PendingJob::SIZE, 6)
                JSHandle<JSHClass> pendingClass(thread,
                    JSHClass::Cast(globalConst->GetPendingJobClass().GetTaggedObject()));
                JSHandle<TaggedObject> pendingJob(thread, factory->NewDynObject(pendingClass));
                DUMP_FOR_HANDLE(pendingJob)
                break;
            }
            case JSType::COMPLETION_RECORD: {
                CHECK_DUMP_FILEDS(Record::SIZE, CompletionRecord::SIZE, 2)
                JSHandle<CompletionRecord> comRecord =
                    factory->NewCompletionRecord(CompletionRecordType::NORMAL, globalEnv->GetEmptyArray());
                DUMP_FOR_HANDLE(comRecord)
                break;
            }
            case JSType::MACHINE_CODE_OBJECT: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), MachineCode::DATA_OFFSET, 1)
                JSHandle<MachineCode>  machineCode = factory->NewMachineCodeObject(16, nullptr);
                DUMP_FOR_HANDLE(machineCode)
                break;
            }
            case JSType::ECMA_MODULE: {
                CHECK_DUMP_FILEDS(ECMAObject::SIZE, EcmaModule::SIZE, 1)
                JSHandle<EcmaModule> ecmaModule = factory->NewEmptyEcmaModule();
                DUMP_FOR_HANDLE(ecmaModule)
                break;
            }
            case JSType::CLASS_INFO_EXTRACTOR: {
#ifdef PANDA_TARGET_64
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), ClassInfoExtractor::SIZE, 10)
#else
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), ClassInfoExtractor::SIZE, 9)
#endif
                JSHandle<ClassInfoExtractor> classInfoExtractor = factory->NewClassInfoExtractor(nullptr);
                DUMP_FOR_HANDLE(classInfoExtractor)
                break;
            }
            case JSType::JS_QUEUE:
            case JSType::JS_API_VECTOR:
            case JSType::JS_API_ARRAY_LIST: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSAPIArrayList::SIZE, 1)
                JSHandle<JSAPIArrayList> jsArrayList = NewJSAPIArrayList(thread, factory, proto);
                DUMP_FOR_HANDLE(jsArrayList)
                break;
            }
            case JSType::JS_API_ARRAYLIST_ITERATOR: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSAPIArrayListIterator::SIZE, 2)
                JSHandle<JSAPIArrayListIterator> jsArrayListIter =
                    factory->NewJSAPIArrayListIterator(NewJSAPIArrayList(thread, factory, proto));
                DUMP_FOR_HANDLE(jsArrayListIter)
                break;
            }
            case JSType::TS_OBJECT_TYPE: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), TSObjectType::SIZE, 3)
                JSHandle<TSObjectType> objectType = factory->NewTSObjectType(0);
                DUMP_FOR_HANDLE(objectType)
                break;
            }
            case JSType::TS_CLASS_TYPE: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), TSClassType::SIZE, 5)
                JSHandle<TSClassType> classType = factory->NewTSClassType();
                DUMP_FOR_HANDLE(classType)
                break;
            }
            case JSType::TS_INTERFACE_TYPE: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), TSInterfaceType::SIZE, 3)
                JSHandle<TSInterfaceType> interfaceType = factory->NewTSInterfaceType();
                DUMP_FOR_HANDLE(interfaceType)
                break;
            }
            case JSType::TS_IMPORT_TYPE: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), TSImportType::SIZE, 3)
                JSHandle<TSImportType> importType = factory->NewTSImportType();
                DUMP_FOR_HANDLE(importType)
                break;
            }
            case JSType::TS_CLASS_INSTANCE_TYPE: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), TSClassInstanceType::SIZE, 2)
                JSHandle<TSClassInstanceType> classInstanceType = factory->NewTSClassInstanceType();
                DUMP_FOR_HANDLE(classInstanceType)
                break;
            }
            case JSType::TS_UNION_TYPE: {
                CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), TSUnionType::SIZE, 2)
                JSHandle<TSUnionType> unionType = factory->NewTSUnionType(1);
                DUMP_FOR_HANDLE(unionType)
                break;
            }
            case JSType::JS_API_TREE_MAP: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSAPITreeMap::SIZE, 1)
                JSHandle<JSAPITreeMap> jsTreeMap = NewJSAPITreeMap(thread, factory);
                DUMP_FOR_HANDLE(jsTreeMap)
                break;
            }
            case JSType::JS_API_TREE_SET: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSAPITreeSet::SIZE, 1)
                JSHandle<JSAPITreeSet> jsTreeSet = NewJSAPITreeSet(thread, factory);
                DUMP_FOR_HANDLE(jsTreeSet)
                break;
            }
            case JSType::JS_API_TREEMAP_ITERATOR: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSAPITreeMapIterator::SIZE, 4)
                JSHandle<JSAPITreeMapIterator> jsTreeMapIter =
                    factory->NewJSAPITreeMapIterator(NewJSAPITreeMap(thread, factory), IterationKind::KEY);
                DUMP_FOR_HANDLE(jsTreeMapIter)
                break;
            }
            case JSType::JS_API_TREESET_ITERATOR: {
                CHECK_DUMP_FILEDS(JSObject::SIZE, JSAPITreeSetIterator::SIZE, 4)
                JSHandle<JSAPITreeSetIterator> jsTreeSetIter =
                    factory->NewJSAPITreeSetIterator(NewJSAPITreeSet(thread, factory), IterationKind::KEY);
                DUMP_FOR_HANDLE(jsTreeSetIter)
                break;
            }
            default:
                LOG_ECMA_MEM(ERROR) << "JSType " << static_cast<int>(type) << " cannot be dumped.";
                UNREACHABLE();
                break;
        }
    }
#undef NEW_OBJECT_AND_DUMP
#undef DUMP_FOR_HANDLE
}
}  // namespace panda::test