/* 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/.
 */
#ifndef _include_jc_code_h_
#define _include_jc_code_h_

#include "Opcodes.h"
#include "Barriers.h"
#include "Heap.h"
#include "Types.h"
#include "FixedArray.h"

namespace ke {

class Module;
class Type;

// A code object contains the bytecode compiled from a function (or global
// script), as well as all information needed to interpret or JIT-compile
// the bytecode.
class Code : public Object
{
    Barriered<Module> module_;
    Barriered<ByteArray> bytecode_;
    Barriered<FixedArray> locals_;
    Barriered<FixedArray> objects_;
    Barriered<FixedArray> strings_;
    Barriered<ByteArray> safepoints_;
    Barriered<ByteArray> sourcemap_;
    unsigned maxStackDepth_;
    unsigned lineNumber_;
    unsigned maxLoopDepth_;

  public:
    static inline size_t BytesPerSafepoint(size_t stackDepth) {
        return (Align(stackDepth, 8) / 8) + sizeof(unsigned);
    }

  public:
    static Code *New(Zone *zone, Handle<ByteArray> bytecode, Handle<FixedArray> locals,
                     Handle<FixedArray> objects, Handle<FixedArray> strings, unsigned maxStackDepth,
                     unsigned maxLoopDepth, Handle<ByteArray> safepoints, Handle<ByteArray> sourcemap);

    Module *module() {
        return module_;
    }
    bytecode *start() {
        return bytecode_->raw();
    }
    unsigned length() {
        return bytecode_->length();
    }
    Type *localType(size_t index) {
        return Type::cast(locals_->at(index));
    }
    unsigned nlocals() {
        return locals_ ? locals_->length() : 0;
    }
    unsigned maxStackDepth() {
        return maxStackDepth_;
    }
    unsigned maxLoopDepth() {
        return maxLoopDepth_;
    }
    Map *map(size_t index) {
        return Map::cast(objects_->at(index));
    }
    Object *object(size_t index) {
        return objects_->at(index);
    }
    ByteArray *safepoints() {
        return safepoints_;
    }
    FixedArray *strings() {
        return strings_;
    }
    uint8 *safepointAt(unsigned pcOffset);

    void setModule(Handle<Module> module) {
        module_ = module;
    }

    unsigned pcToOffset(bytecode *pc) {
        assert(pc >= start() && pc < start() + length());
        return unsigned(pc - start());
    }

    SourcePosition pcToSource(unsigned pc);
    unsigned lineNumber() {
        return lineNumber_;
    }

    // GC Descriptor.
    static inline size_t offsetOfModule() {
        return OFFSETOF(Code, module_);
    }
    static inline size_t offsetOfBytecode() {
        return OFFSETOF(Code, bytecode_);
    }
    static inline size_t offsetOfLocals() {
        return OFFSETOF(Code, locals_);
    }
    static inline size_t offsetOfObjects() {
        return OFFSETOF(Code, objects_);
    }
    static inline size_t offsetOfStrings() {
        return OFFSETOF(Code, strings_);
    }
    static inline size_t offsetOfSafepoints() {
        return OFFSETOF(Code, safepoints_);
    }
    static inline size_t offsetOfSourceMap() {
        return OFFSETOF(Code, sourcemap_);
    }
    // End GC Descriptor.

    static Code *cast(Object *obj) {
        assert(!obj || obj->is(MapKind_Code));
        return reinterpret_cast<Code *>(obj);
    }
};

}

#endif // _include_jc_code_h_
