/*
 * Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
 * that can be found in the LICENSE file.
 */

#include "FinalizerHooks.hpp"

#include "Cleaner.h"
#include "Memory.h"
#include "Types.h"

using namespace kotlin;

namespace {

void (*g_hookOverrideForTesting)(ObjHeader*) = nullptr;

// Not inlining this call as it affects deallocation performance for
// all types.
NO_INLINE void RunFinalizerHooksImpl(ObjHeader* object, const TypeInfo* type) noexcept {
    if (g_hookOverrideForTesting != nullptr) {
        g_hookOverrideForTesting(object);
    }
    // TODO: Consider some global registration.
    if (type == theCleanerImplTypeInfo) {
        DisposeCleaner(object);
    } else if (type == theRegularWeakReferenceImplTypeInfo) {
        DisposeRegularWeakReferenceImpl(object);
    }
}

} // namespace

PERFORMANCE_INLINE bool kotlin::HasFinalizers(ObjHeader* object) noexcept {
    return object->has_meta_object() || HasFinalizersDataInObject(object);
}

PERFORMANCE_INLINE bool kotlin::HasFinalizersDataInObject(ObjHeader* object) noexcept {
    return (object->type_info()->flags_ & TF_HAS_FINALIZER) != 0;
}

PERFORMANCE_INLINE void kotlin::RunFinalizers(ObjHeader* object) noexcept {
    auto* type = object->type_info();
    if ((type->flags_ & TF_HAS_FINALIZER) != 0) {
        // This is a cold path.
        RunFinalizerHooksImpl(object, type);
    }
    if (object->has_meta_object()) {
        ObjHeader::destroyMetaObject(object);
    }
}

void kotlin::SetFinalizerHookForTesting(void (*hook)(ObjHeader*)) noexcept {
    g_hookOverrideForTesting = hook;
}
