/* vim: set ts=4 sw=4 tw=99 et:
 *
 * Copyright (C) 2012 David Anderson
 *
 * This file is part of JITCraft.
 *
 * JITCraft is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 * 
 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * JITCraft. If not, see http://www.gnu.org/licenses/.
 */
#include <stdlib.h>
#include "BytecodeEmitter.h"
#include "Utility.h"
#include "Types.h"

using namespace ke;

BytecodeEmitter::BytecodeEmitter(PoolAllocator &pool)
  : pool_(pool),
    buffer_(inline_buffer_),
    buffer_pos_(buffer_),
    buffer_end_(buffer_pos_ + ARRAY_LENGTH(inline_buffer_)),
    oom_(false),
    maxStackDepth_(0)
{
}

bool
BytecodeEmitter::growBuffer(size_t nbytes)
{
    if (oom_) {
        buffer_pos_ = buffer_;
        return false;
    }

    size_t newSize = size_t((buffer_end_ - buffer_) * 2);
    if (newSize >= MAX_LENGTH) {
        oom_ = true;
        buffer_pos_ = buffer_;
        return false;
    }

    bytecode *newBuffer;
    if (buffer_ == inline_buffer_)
        newBuffer = (bytecode *)malloc(nbytes);
    else
        newBuffer = (bytecode *)realloc(buffer_, newSize);

    // If we can't allocate a buffer, reset the buffer to the start and set
    // a flag to indicate out-of-memory.
    if (!newBuffer) {
        oom_ = true;
        buffer_pos_ = buffer_;
        return false;
    }

    buffer_pos_ = newBuffer + size_t(buffer_pos_ - buffer_);
    buffer_ = newBuffer;
    buffer_end_ = buffer_ + newSize;
    return true;
}

void
BytecodeEmitter::recordOops()
{
    OopRecord *record = new (pool_) OopRecord(oopMap_.length(), position());

    record->slots = (bool *)pool_.allocate(record->depth);
    if (!record->slots) {
        oom_ = true;
        return;
    }

    bool hadOops = false;
    for (size_t i = 0; i < oopMap_.length(); i++) {
        bool bit = oopMap_[i];
        record->slots[i] = bit;
        hadOops |= bit;
    }

    if (!hadOops)
        return;

    oom_ &= oopRecords_.append(record);
}

