/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */
/* Header files */
#ifdef VX
#include <taskLib.h>
#endif
#include <stdio.h>
#include "js-runtime.h"
#include "js-runtimeexception.h"
#include "js-exceptionhandler.h"
#include "js-gcheap.h"
#if defined CONF_WPAD
#include "js-dbg.h"
#endif
#if 0
#include "ewb-sys.h"
#include "ewb-sys-if.h"
#else
extern "C" {
	extern void EwbNotifyError(const unsigned char);
	extern void EwbSetLog(char *);
}
#define EWB_ERROR_JS_MEMORY 4
#endif
/* Classes */ size_t
JSGCHeap::Allocator::extractSize(void *ptr)
{
/* if you use this Function, it cause Purify Memory ERROR!! */
#ifdef VX
	return ((int *)ptr)[-1] - 8;
#else
	return ((int *)ptr)[-2] & ~0x7;
#endif
}
size_t JSGCHeap::Allocator::getRealdl_mallocSize(void *ptr)
{
#if defined(TARGET_OS_LINUX)
	if (!ptr) {
		return 0;
	}
	return ((size_t*)ptr)[-1];
#else ///< TARGET_OS_LINUX
/* this Funxtion is not use without "dl_malloc" on VX-Works */
#if !defined CONF_WPAD
	return ((int *)ptr)[-1];
#else
	return ((int *)ptr)[-3];
#endif
#endif
}

void *JSGCHeap::Allocator::memalign(size_t alignment, size_t size)
{
#if defined(VX) || defined(TARGET_OS_LINUX)
	if (bytes + size > (size_t) maxBytes - 60000) { /* -60000 avoid to gc header can not allocate */
#if defined CONF_WPAD
		ApdJsErrorNotify(NULL, "JSGCHeap::Allocator::memalign(alignment=%u, size=%d) failed, bytes=%d, maxBytes=%d\n", alignment, size, bytes, maxBytes);
#endif
		return NULL;
	}
#endif ///< VX || TARGET_OS_LINUX

	void *ptr = runtime->localHeap.memalign(alignment, size);

	if (ptr != NULL) {
#if defined(VX) || defined(TARGET_OS_LINUX)
		bytes += getRealdl_mallocSize(ptr);
#else
		//bytes += size ;
#endif ///< VX || TARGET_OS_LINUX
	}
	return ptr;
}

void *JSGCHeap::Allocator::malloc(size_t size)
{
#if defined(VX) || defined(TARGET_OS_LINUX)
	if (bytes + size > (size_t) maxBytes) {
#if defined CONF_WPAD
		ApdJsErrorNotify(NULL, "JSGCHeap::Allocator::malloc(size=%d) failed, bytes=%d, maxBytes=%d\n", size, bytes, maxBytes);
#endif
		return NULL;
	}
#endif ///< VX || TARGET_OS_LINUX

	void *ptr = runtime->localHeap.malloc(size);

	if (ptr != NULL) {
#if defined(VX) || defined(TARGET_OS_LINUX)
		//printf("JSGC malloc extractSize:%d RealSize:%d size:%d\n",extractSize(ptr),getRealdl_mallocSize(ptr),size);
		bytes += getRealdl_mallocSize(ptr);
#else
		//bytes += size ;
#endif ///< VX || TARGET_OS_LINUX
	}
	return ptr;
}
void JSGCHeap::Allocator::free(void *ptr)
{
	if (ptr != NULL) {
#if defined(VX) || defined(TARGET_OS_LINUX)
		bytes -= getRealdl_mallocSize(ptr);
		//printf("JSGC free extractSize:%d getRealdl_mallocSize:%d\n",extractSize(ptr),getRealdl_mallocSize(ptr));
#endif ///< VX || TARGET_OS_LINUX

		runtime->localHeap.free(ptr);

	}
}
void JSGCHeap::Allocator::markAll()
{
	runtime->markAll();
}
void JSGCHeap::Allocator::finalize(void *obj)
{
	JSGCNew *gcObj = (JSGCNew *) obj;

	gcObj->finalize(JSContext::getCurrentContext());
}

void JSGCHeap::Allocator::stopWorld()
{
	// printf("JSGCHeap::stopWorld 0: ### %d %d\n", maxBytes, bytes);
	runtime->stopWorld();
}

void JSGCHeap::Allocator::resumeWorld()
{
#ifndef SHELL
#ifdef STATS
	extern int ewbPrintOn;
	if (ewbPrintOn) {
		printf("JSGCHeap::resumeWorld 0: limit = %d bytes, allocated = %d bytes\n", maxBytes, bytes);
	}
#endif
#endif
	runtime->resumeWorld();
}
JSGCHeap::Allocator::Allocator(JSRuntime * runtime, int maxBytes)
{
	this->runtime = runtime;
	this->maxBytes = maxBytes;
	bytes = 0;
}

#ifdef THREADS
void JSGCHeap::MutexListener::lock()
{
	runtime->lock();
}

void JSGCHeap::MutexListener::unlock()
{
	runtime->unlock();
}

JSGCHeap::MutexListener::MutexListener(JSRuntime * runtime)
{
	this->runtime = runtime;
}
#endif

void *JSGCHeap::newNormalObj(JSContext * cx, size_t size)
{
	void *ptr = malloc(size, NORMAL);

	if (ptr != NULL) {
		cx->addNewBorn(ptr);
		return ptr;
	}
#ifndef SHELL
	EwbSetLog("JS GCobj Memory Exhaused. Be necessary to expand JS GCobj Memory\n");
	EwbNotifyError(EWB_ERROR_JS_MEMORY);    //20051222 ichino
#endif
#if SUNOS5
	exit(1);
#elif defined(VX)
	//taskSuspend(NULL);
#endif
#if defined CONF_WPAD
	ApdJsErrorNotify(cx, "JSGCHeap::newNormalObj: malloc(%d, NORMAL) failed\n", size);
#if defined CONF_WPAD_DEBUG
	ApdJsShowMemPart(cx, "JSGCHeap::newNormalObj");
#endif
#endif
	cx->exceptionHandler->throwEx(cx->outOfMemory);
	/* not reached */
	return NULL;
}

void *JSGCHeap::newObj(JSContext * cx, size_t size)
{
	void *ptr = malloc(size, PTRFREE);

	if (ptr != NULL) {
		cx->addNewBorn(ptr);
		return ptr;
	}
#ifndef SHELL
	EwbSetLog("JS GC Memory Exhaused. Be necessary to expand JS GC Memory\n");
	EwbNotifyError(EWB_ERROR_JS_MEMORY);    //20051222 ichino
#endif
#if SUNOS5
	exit(1);
#elif defined(VX)
	//taskSuspend(NULL);
#endif
#if defined CONF_WPAD
	ApdJsErrorNotify(cx, "JSGCHeap::newObj: malloc(%d, PTRFREE) failed\n", size);
#if defined CONF_WPAD_DEBUG
	ApdJsShowMemPart(cx, "JSGCHeap::newObj");
#endif
#endif
	cx->exceptionHandler->throwEx(cx->outOfMemory);
	/* not reached */
	return NULL;
}

JSGCHeap::JSGCHeap(JSRuntime * runtime, int maxBytes)
#ifdef THREADS
:      allocator(runtime, maxBytes), mutexListener(runtime)
#else
:      allocator(runtime, maxBytes)
#endif
{
	setMemoryAllocator(&allocator);
	setPhaseListener(&allocator);
#ifdef THREADS
	setMutexListener(&mutexListener);
#endif
}
