/*
 * Copyright (C) 2009 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. 
 */

#ifndef CodeLocation_h
#define CodeLocation_h

#include "MacroAssemblerCodeRef.h"

#if ENABLE(ASSEMBLER)

namespace JSC {

class CodeLocationInstruction;
class CodeLocationLabel;
class CodeLocationJump;
class CodeLocationCall;
class CodeLocationNearCall;
class CodeLocationDataLabel32;
class CodeLocationDataLabelPtr;

// The CodeLocation* types are all pretty much do-nothing wrappers around
// CodePtr (or MacroAssemblerCodePtr, to give it its full name).  These
// classes only exist to provide type-safety when linking and patching code.
//
// The one new piece of functionallity introduced by these classes is the
// ability to create (or put another way, to re-discover) another CodeLocation
// at an offset from one you already know.  When patching code to optimize it
// we often want to patch a number of instructions that are short, fixed
// offsets apart.  To reduce memory overhead we will only retain a pointer to
// one of the instructions, and we will use the *AtOffset methods provided by
// CodeLocationCommon to find the other points in the code to modify.
class CodeLocationCommon : public MacroAssemblerCodePtr {
public:
    CodeLocationInstruction instructionAtOffset(int offset);
    CodeLocationLabel labelAtOffset(int offset);
    CodeLocationJump jumpAtOffset(int offset);
    CodeLocationCall callAtOffset(int offset);
    CodeLocationNearCall nearCallAtOffset(int offset);
    CodeLocationDataLabelPtr dataLabelPtrAtOffset(int offset);
    CodeLocationDataLabel32 dataLabel32AtOffset(int offset);

protected:
    CodeLocationCommon()
    {
    }

    CodeLocationCommon(MacroAssemblerCodePtr location)
        : MacroAssemblerCodePtr(location)
    {
    }
};

class CodeLocationInstruction : public CodeLocationCommon {
public:
    CodeLocationInstruction() {}
    explicit CodeLocationInstruction(MacroAssemblerCodePtr location)
        : CodeLocationCommon(location) {}
    explicit CodeLocationInstruction(void* location)
        : CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
};

class CodeLocationLabel : public CodeLocationCommon {
public:
    CodeLocationLabel() {}
    explicit CodeLocationLabel(MacroAssemblerCodePtr location)
        : CodeLocationCommon(location) {}
    explicit CodeLocationLabel(void* location)
        : CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
};

class CodeLocationJump : public CodeLocationCommon {
public:
    CodeLocationJump() {}
    explicit CodeLocationJump(MacroAssemblerCodePtr location)
        : CodeLocationCommon(location) {}
    explicit CodeLocationJump(void* location)
        : CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
};

class CodeLocationCall : public CodeLocationCommon {
public:
    CodeLocationCall() {}
    explicit CodeLocationCall(MacroAssemblerCodePtr location)
        : CodeLocationCommon(location) {}
    explicit CodeLocationCall(void* location)
        : CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
};

class CodeLocationNearCall : public CodeLocationCommon {
public:
    CodeLocationNearCall() {}
    explicit CodeLocationNearCall(MacroAssemblerCodePtr location)
        : CodeLocationCommon(location) {}
    explicit CodeLocationNearCall(void* location)
        : CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
};

class CodeLocationDataLabel32 : public CodeLocationCommon {
public:
    CodeLocationDataLabel32() {}
    explicit CodeLocationDataLabel32(MacroAssemblerCodePtr location)
        : CodeLocationCommon(location) {}
    explicit CodeLocationDataLabel32(void* location)
        : CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
};

class CodeLocationDataLabelPtr : public CodeLocationCommon {
public:
    CodeLocationDataLabelPtr() {}
    explicit CodeLocationDataLabelPtr(MacroAssemblerCodePtr location)
        : CodeLocationCommon(location) {}
    explicit CodeLocationDataLabelPtr(void* location)
        : CodeLocationCommon(MacroAssemblerCodePtr(location)) {}
};

inline CodeLocationInstruction CodeLocationCommon::instructionAtOffset(int offset)
{
    ASSERT_VALID_CODE_OFFSET(offset);
    return CodeLocationInstruction(reinterpret_cast<char*>(dataLocation()) + offset);
}

inline CodeLocationLabel CodeLocationCommon::labelAtOffset(int offset)
{
    ASSERT_VALID_CODE_OFFSET(offset);
    return CodeLocationLabel(reinterpret_cast<char*>(dataLocation()) + offset);
}

inline CodeLocationJump CodeLocationCommon::jumpAtOffset(int offset)
{
    ASSERT_VALID_CODE_OFFSET(offset);
    return CodeLocationJump(reinterpret_cast<char*>(dataLocation()) + offset);
}

inline CodeLocationCall CodeLocationCommon::callAtOffset(int offset)
{
    ASSERT_VALID_CODE_OFFSET(offset);
    return CodeLocationCall(reinterpret_cast<char*>(dataLocation()) + offset);
}

inline CodeLocationNearCall CodeLocationCommon::nearCallAtOffset(int offset)
{
    ASSERT_VALID_CODE_OFFSET(offset);
    return CodeLocationNearCall(reinterpret_cast<char*>(dataLocation()) + offset);
}

inline CodeLocationDataLabelPtr CodeLocationCommon::dataLabelPtrAtOffset(int offset)
{
    ASSERT_VALID_CODE_OFFSET(offset);
    return CodeLocationDataLabelPtr(reinterpret_cast<char*>(dataLocation()) + offset);
}

inline CodeLocationDataLabel32 CodeLocationCommon::dataLabel32AtOffset(int offset)
{
    ASSERT_VALID_CODE_OFFSET(offset);
    return CodeLocationDataLabel32(reinterpret_cast<char*>(dataLocation()) + offset);
}

} // namespace JSC

#endif // ENABLE(ASSEMBLER)

#endif // CodeLocation_h