/*******************************************************************************
 * Copyright IBM Corp. and others 2025
 *
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License 2.0 which accompanies this
 * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
 * or the Apache License, Version 2.0 which accompanies this distribution
 * and is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License, v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception [1] and GNU General Public
 * License, version 2 with the OpenJDK Assembly Exception [2].
 *
 * [1] https://www.gnu.org/software/classpath/license.html
 * [2] https://openjdk.org/legal/assembly-exception.html
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
 *******************************************************************************/

#include "env/OMRRetainedMethodSet.hpp"

#include "compile/Compilation.hpp"
#include "compile/ResolvedMethod.hpp"
#include "infra/Assert.hpp"

OMR::RetainedMethodSet::KeepalivesAndBonds::KeepalivesAndBonds(TR::Region &heapRegion)
    : _keepaliveMethods(heapRegion)
    , _bondMethods(heapRegion)
{
    // empty
}

OMR::RetainedMethodSet::RetainedMethodSet(TR::Compilation *comp, TR_ResolvedMethod *method,
    OMR::RetainedMethodSet *parent)
    : _comp(comp)
    , _method(method)
    , _parent(parent)
    , _keepalivesAndBonds(parent == NULL ? NULL // lazily initialized to avoid calling virtual method in ctor
                                         : parent->keepalivesAndBonds())
{
    // empty
}

void OMR::RetainedMethodSet::keepalive()
{
    void *key = unloadingKey(_method);
    traceCommitment("keepalive", key);
    keepalivesAndBonds()->_keepaliveMethods.insert(std::make_pair(key, _method));
}

void OMR::RetainedMethodSet::bond()
{
    void *key = unloadingKey(_method);
    traceCommitment("bond", key);
    keepalivesAndBonds()->_bondMethods.insert(std::make_pair(key, _method));
}

OMR::RetainedMethodSet::KeepalivesAndBonds *OMR::RetainedMethodSet::keepalivesAndBonds()
{
    if (_keepalivesAndBonds == NULL) {
        _keepalivesAndBonds = createKeepalivesAndBonds();
        TR_ASSERT_FATAL(_keepalivesAndBonds != NULL, "createKeepalivesAndBonds() returned null");
    }

    return _keepalivesAndBonds;
}

OMR::RetainedMethodSet::KeepalivesAndBonds *OMR::RetainedMethodSet::createKeepalivesAndBonds()
{
    return new (comp()->region()) KeepalivesAndBonds(comp()->region());
}

void OMR::RetainedMethodSet::traceCommitment(const char *kind, void *key)
{
    if (_comp->getOption(TR_TraceRetainedMethods)) {
        traceMsg(_comp, "RetainedMethodSet %p: %s %p %.*s.%.*s%.*s (key %p)\n", this, kind,
            _method->getNonPersistentIdentifier(), _method->classNameLength(), _method->classNameChars(),
            _method->nameLength(), _method->nameChars(), _method->signatureLength(), _method->signatureChars(), key);
    }
}

OMR::RetainedMethodSet *OMR::RetainedMethodSet::createChild(TR_ResolvedMethod *method)
{
    TR_ASSERT_FATAL(false, "unimplemented: OMR::RetainedMethodSet::createChild");
    return NULL;
}

OMR::RetainedMethodSet *OMR::RetainedMethodSet::withLinkedCalleeAttested(TR_ByteCodeInfo bci) { return this; }

OMR::RetainedMethodSet *OMR::RetainedMethodSet::withKeepalivesAttested() { return this; }

OMR::RetainedMethodSet *OMR::RetainedMethodSet::withBondsAttested() { return this; }

void *OMR::RetainedMethodSet::unloadingKey(TR_ResolvedMethod *method) { return method->getNonPersistentIdentifier(); }
