/****************************************************************************
 * 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_VirtualMachineCode_struct_init(Ctx *ctx, knh_VirtualMachineCode *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_VirtualMachineCode_struct_copy(Ctx *ctx, knh_VirtualMachineCode *b, knh_VirtualMachineCode *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_VirtualMachineCode_struct_compare  NULL

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

void
knh_VirtualMachineCode_struct_traverse(Ctx *ctx, knh_VirtualMachineCode *b, f_traverse gc)
{
	knh_VirtualMachineCode_utraverse(ctx, new_bytes__2(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] */

VirtualMachineCode* new_VirtualMachineCode(Ctx *ctx, knh_fileid_t fileid, knh_bytes_t elf, knh_bytes_t dwarf)
{
	knh_VirtualMachineCode_t *o = 
		(VirtualMachineCode*)new_Object__RAW(ctx, FLAG_VirtualMachineCode, CLASS_VirtualMachineCode, sizeof(knh_VirtualMachineCode));
	knh_VirtualMachineCode_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_VirtualMachineCode_exec(Ctx *ctx, knh_sfp_t *sfp);

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

void knh_Method_setVirtualMachineCode(Ctx *ctx, Method *mtd, VirtualMachineCode *code)
{
	KNH_ASSERT(IS_VirtualMachineCode(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_VirtualMachineCode_exec;
	mtd->fcall_1  = knh_VirtualMachineCode_exec;
	mtd->code_2   = NULL; //DP(code)->code;
}

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

knh_bytes_t knh_VirtualMachineCode_tobytes(VirtualMachineCode *o)
{
	KNH_ASSERT(IS_VirtualMachineCode(o));
	return new_bytes__2(DP(o)->code, DP(o)->size);
}

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

int knh_Method_pctoline(Method *mtd, knhvmc_t *pc)
{
	if(!knh_Method_isObjectCode(mtd) || !IS_VirtualMachineCode((Object*)DP(mtd)->code)) {
		return 0;
	}
	else {
		VirtualMachineCode *o = (VirtualMachineCode*)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
