/****************************************************************************
 * KONOHA COPYRIGHT, LICENSE NOTICE, AND DISCRIMER
 *
 * Copyright (c) 2005-2008, Kimio Kuramitsu <kimio at ynu.ac.jp>
 *           (c) 2008-      Konoha Software Foundation
 * All rights reserved.
 *
 * You may choose one of the following two licenses when you use konoha.
 * See www.konohaware.org/license.html for further information.
 *
 * (1) GNU General Public License 2.0      (with    KONOHA_UNDER_GPL2)
 * (2) Konoha Software Foundation License 1.0
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "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 THE COPYRIGHT OWNER
 * 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"commons.h"

/* ************************************************************************ */

#ifdef __cplusplus
extern "C" {
#endif

/* ======================================================================== */
/* [structs] */

void
knh_KLRCode_struct_init(Ctx *ctx, knh_KLRCode_struct *b, int init, Object *cs)
{
	b->size = 0;
	b->code = (knhvmc_t*)"";
	b->fileid = 0;
	b->nsid = 0;
	b->dwarf = NULL;
	b->dsize = 0;
}

/* ------------------------------------------------------------------------ */

void
knh_KLRCode_struct_copy(Ctx *ctx, knh_KLRCode_struct *b, knh_KLRCode_struct *b2)
{
	b2->size = b->size;
	b2->code = (knhvmc_t*)KNH_MALLOC(ctx, KNH_SIZE(b->size));
	knh_memcpy(b2->code, b->code, b2->size);

	b2->fileid = b->fileid;
	b2->nsid = b->nsid;
	b2->dsize = b->dsize;
	b2->dwarf = (knh_dwarf_t*)KNH_MALLOC(ctx, b2->dsize * sizeof(knh_dwarf_t));
	knh_memcpy(b2->dwarf, b->dwarf, b2->dsize);
}

/* ------------------------------------------------------------------------ */

#define _knh_KLRCode_struct_compare  NULL

/* ------------------------------------------------------------------------ */

void
knh_KLRCode_struct_traverse(Ctx *ctx, knh_KLRCode_struct *b, f_traverse gc)
{
	knh_KLRCode_utraverse(ctx, new_bytes__2((char*)b->code, b->size), gc);
	if(IS_SWEEP(gc)) {
		KNH_FREE(b->code, KNH_SIZE(b->size));
		if(b->dwarf != NULL) {
			KNH_FREE(b->dwarf, b->dsize * sizeof(knh_dwarf_t));
		}
	}
}

/* ======================================================================== */
/* [constructors] */

KLRCode* new_KLRCode(Ctx *ctx, knh_fileid_t fileid, knh_bytes_t elf, knh_bytes_t dwarf)
{
	knh_KLRCode_t *o =
		(KLRCode*)new_Object_malloc(ctx, FLAG_KLRCode, CLASS_KLRCode, sizeof(knh_KLRCode_struct));
	knh_KLRCode_struct_init(ctx, DP(o), 0, NULL);

	DP(o)->fileid = fileid;

	DP(o)->code = (knhvmc_t*)KNH_MALLOC(ctx, KNH_SIZE(elf.len));
	DP(o)->size = elf.len;
	knh_memcpy(DP(o)->code, elf.buf, elf.len);

	KNH_ASSERT(dwarf.len % sizeof(knh_dwarf_t) == 0);
	DP(o)->dsize = dwarf.len / sizeof(knh_dwarf_t);
	DP(o)->dwarf = (knh_dwarf_t*)KNH_MALLOC(ctx, DP(o)->dsize * sizeof(knh_dwarf_t));
	knh_memcpy(DP(o)->dwarf, dwarf.buf, dwarf.len);
	//DEBUG3("code=%p dwarf=%p", DP(o)->code, DP(o)->dwarf);
	return o;
}

/* ======================================================================== */
/* [methods] */

METHOD knh_KLRCode_exec(Ctx *ctx, knh_sfp_t *sfp);

/* ------------------------------------------------------------------------ */

void knh_Method_setKLRCode(Ctx *ctx, Method *mtd, KLRCode *code)
{
	KNH_ASSERT(IS_KLRCode(code));
	if(knh_Method_isObjectCode(mtd)) {
		KNH_SETv(ctx, DP(mtd)->code, code);
	}else {
		KNH_INITv(DP(mtd)->code, code);
		knh_Method_setObjectCode(mtd, 1);
	}
	DP(mtd)->func = knh_KLRCode_exec;
	mtd->fcall_1  = knh_KLRCode_exec;
	mtd->code_2   = NULL; //DP(code)->code;
}

///* ------------------------------------------------------------------------ */
//
//INLINE
//KLRCode *knh_Method_vmc(Method *b)
//{
//	KNH_ASSERT(IS_KLRCode(DP(o)->code));
//	return (KLRCode*)DP(o)->code;
//}
//
/* ------------------------------------------------------------------------ */

knh_bytes_t knh_KLRCode_tobytes(KLRCode *o)
{
	KNH_ASSERT(IS_KLRCode(o));
	return new_bytes__2((char*)DP(o)->code, DP(o)->size);
}

///* ------------------------------------------------------------------------ */
//
//INLINE
//knh_bytes_t knh_stackf_vmc(Ctx *ctx, Object **sf)
//{
//	return knh_KLRCode_tobytes((KLRCode*)knh_Method_vmc(sf[-1]));
//}
//
///* ------------------------------------------------------------------------ */
//
//INLINE
//knh_vmc_t *knh_KLRCode_pc(KLRCode *b)
//{
//	return DP(o)->code;
//}
//
///* ------------------------------------------------------------------------ */
//
//char *knh_Method_file(Method *mtd, knh_vmc_t *pc)
//{
//	if(!knh_Method_isObjectCode(mtd) || !IS_KLRCode(mtd->code)) {
//		return "(unknown)";
//	}
//	return FILEN(((KLRCode*)mtd->code)->fileid);
//}
//
///* ------------------------------------------------------------------------ */

int knh_Method_pctoline(Method *mtd, knhvmc_t *pc)
{
	if(!knh_Method_isObjectCode(mtd) || !IS_KLRCode((Object*)DP(mtd)->code)) {
		return 0;
	}
	else {
		KLRCode *o = (KLRCode*)DP(mtd)->code;
		if(DP(o)->dwarf == NULL && DP(o)->dsize > 0) {
			return 0;
		}
		else {
			int i = 0, offset = pc - DP(o)->code;
			for(i = 0; i < DP(o)->dsize - 1; i++) {
				if(DP(o)->dwarf[i].offset <= offset && offset < DP(o)->dwarf[i+1].offset) {
					return DP(o)->dwarf[i].line;
				}
			}
			return DP(o)->dwarf[DP(o)->dsize-1].line;
		}
	}
}


/* ------------------------------------------------------------------------ */

#ifdef __cplusplus
}
#endif
