/*
 * Copyright (C) 2018 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */

#include "config.h"
#include "InstanceOfStatus.h"

#include "ICStatusUtils.h"
#include "InstanceOfAccessCase.h"
#include "JSCInlines.h"
#include "PolymorphicAccess.h"
#include "StructureStubInfo.h"

namespace JSC {

void InstanceOfStatus::appendVariant(const InstanceOfVariant& variant)
{
    appendICStatusVariant(m_variants, variant);
}

InstanceOfStatus InstanceOfStatus::computeFor(
    CodeBlock* codeBlock, ICStatusMap& infoMap, BytecodeIndex bytecodeIndex)
{
    ConcurrentJSLocker locker(codeBlock->m_lock);
    
    InstanceOfStatus result;
#if ENABLE(DFG_JIT)
    result = computeForStubInfo(locker, infoMap.get(CodeOrigin(bytecodeIndex)).stubInfo);

    if (!result.takesSlowPath()) {
        UnlinkedCodeBlock* unlinkedCodeBlock = codeBlock->unlinkedCodeBlock();
        ConcurrentJSLocker locker(unlinkedCodeBlock->m_lock);
        // We also check for BadType here in case this is "primitive instanceof Foo".
        if (unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadCache))
            || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadConstantCache))
            || unlinkedCodeBlock->hasExitSite(locker, DFG::FrequentExitSite(bytecodeIndex, BadType)))
            return TakesSlowPath;
    }
#else
    UNUSED_PARAM(infoMap);
    UNUSED_PARAM(bytecodeIndex);
#endif
    
    return result;
}

#if ENABLE(DFG_JIT)
InstanceOfStatus InstanceOfStatus::computeForStubInfo(const ConcurrentJSLocker&, StructureStubInfo* stubInfo)
{
    // FIXME: We wouldn't have to bail for nonCell if we taught MatchStructure how to handle non
    // cells. If we fixed that then we wouldn't be able to use summary();
    // https://bugs.webkit.org/show_bug.cgi?id=185784
    StubInfoSummary summary = StructureStubInfo::summary(stubInfo);
    if (!isInlineable(summary))
        return InstanceOfStatus(summary);
    
    if (stubInfo->cacheType() != CacheType::Stub)
        return TakesSlowPath; // This is conservative. It could be that we have no information.
    
    PolymorphicAccess* list = stubInfo->u.stub;
    InstanceOfStatus result;
    for (unsigned listIndex = 0; listIndex < list->size(); ++listIndex) {
        const AccessCase& access = list->at(listIndex);
        
        if (access.type() == AccessCase::InstanceOfGeneric)
            return TakesSlowPath;
        
        if (!access.conditionSet().structuresEnsureValidity())
            return TakesSlowPath;
        
        result.appendVariant(InstanceOfVariant(
            access.structure(),
            access.conditionSet(),
            access.as<InstanceOfAccessCase>().prototype(),
            access.type() == AccessCase::InstanceOfHit));
    }
    
    return result;
}
#endif // ENABLE(DFG_JIT)

JSObject* InstanceOfStatus::commonPrototype() const
{
    JSObject* prototype = nullptr;
    for (const InstanceOfVariant& variant : m_variants) {
        if (!prototype) {
            prototype = variant.prototype();
            continue;
        }
        if (prototype != variant.prototype())
            return nullptr;
    }
    return prototype;
}

void InstanceOfStatus::filter(const StructureSet& structureSet)
{
    if (m_state != Simple)
        return;
    filterICStatusVariants(m_variants, structureSet);
    if (m_variants.isEmpty())
        m_state = NoInformation;
}

} // namespace JSC

