/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "jit/BytecodeAnalysis.h"
#include "jsopcode.h"
#include "jsopcodeinlines.h"

using namespace js;
using namespace js::jit;

BytecodeAnalysis::BytecodeAnalysis(JSScript *script)
  : script_(script),
    infos_()
{
}

bool
BytecodeAnalysis::init()
{
    if (!infos_.growByUninitialized(script_->length))
        return false;

    jsbytecode *end = script_->code + script_->length;

    // Clear all BytecodeInfo.
    mozilla::PodZero(infos_.begin(), infos_.length());
    infos_[0].init(/*stackDepth=*/0);

    for (jsbytecode *pc = script_->code; pc < end; pc += GetBytecodeLength(pc)) {
        JSOp op = JSOp(*pc);
        unsigned offset = pc - script_->code;

        IonSpew(IonSpew_BaselineOp, "Analyzing op @ %d (end=%d): %s",
                int(pc - script_->code), int(end - script_->code), js_CodeName[op]);

        // If this bytecode info has not yet been initialized, it's not reachable.
        if (!infos_[offset].initialized)
            continue;


        unsigned stackDepth = infos_[offset].stackDepth;
#ifdef DEBUG
        for (jsbytecode *chkpc = pc + 1; chkpc < (pc + GetBytecodeLength(pc)); chkpc++)
            JS_ASSERT(!infos_[chkpc - script_->code].initialized);
#endif

        unsigned nuses = GetUseCount(script_, offset);
        unsigned ndefs = GetDefCount(script_, offset);

        JS_ASSERT(stackDepth >= nuses);
        stackDepth -= nuses;
        stackDepth += ndefs;

        // If stack depth exceeds max allowed by analysis, fail fast.
        JS_ASSERT(stackDepth <= BytecodeInfo::MAX_STACK_DEPTH);

        if (op == JSOP_TABLESWITCH) {
            unsigned defaultOffset = offset + GET_JUMP_OFFSET(pc);
            jsbytecode *pc2 = pc + JUMP_OFFSET_LEN;
            int32_t low = GET_JUMP_OFFSET(pc2);
            pc2 += JUMP_OFFSET_LEN;
            int32_t high = GET_JUMP_OFFSET(pc2);
            pc2 += JUMP_OFFSET_LEN;

            infos_[defaultOffset].init(stackDepth);
            infos_[defaultOffset].jumpTarget = true;

            for (int32_t i = low; i <= high; i++) {
                unsigned targetOffset = offset + GET_JUMP_OFFSET(pc2);
                if (targetOffset != offset) {
                    infos_[targetOffset].init(stackDepth);
                    infos_[targetOffset].jumpTarget = true;
                }
                pc2 += JUMP_OFFSET_LEN;
            }
        } else if (op == JSOP_TRY) {
            JSTryNote *tn = script_->trynotes()->vector;
            JSTryNote *tnlimit = tn + script_->trynotes()->length;
            for (; tn < tnlimit; tn++) {
                unsigned startOffset = script_->mainOffset + tn->start;
                if (startOffset == offset + 1) {
                    unsigned catchOffset = startOffset + tn->length;

                    if (tn->kind != JSTRY_ITER) {
                        infos_[catchOffset].init(stackDepth);
                        infos_[catchOffset].jumpTarget = true;
                    }
                }
            }
        }

        bool jump = IsJumpOpcode(op);
        if (jump) {
            // Case instructions do not push the lvalue back when branching.
            unsigned newStackDepth = stackDepth;
            if (op == JSOP_CASE)
                newStackDepth--;

            unsigned targetOffset = offset + GET_JUMP_OFFSET(pc);

            // If this is a a backedge to an un-analyzed segment, analyze from there.
            bool jumpBack = (targetOffset < offset) && !infos_[targetOffset].initialized;

            infos_[targetOffset].init(newStackDepth);
            infos_[targetOffset].jumpTarget = true;

            if (jumpBack)
                pc = script_->code + targetOffset;
        }

        // Handle any fallthrough from this opcode.
        if (BytecodeFallsThrough(op)) {
            jsbytecode *nextpc = pc + GetBytecodeLength(pc);
            JS_ASSERT(nextpc < end);
            unsigned nextOffset = nextpc - script_->code;

            infos_[nextOffset].init(stackDepth);

            if (jump)
                infos_[nextOffset].jumpFallthrough = true;

            // Treat the fallthrough of a branch instruction as a jump target.
            if (jump)
                infos_[nextOffset].jumpTarget = true;
            else
                infos_[nextOffset].fallthrough = true;
        }
    }

    return true;
}
