/*
 * 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"
#include "ewb-sys.h"
#include "ewb-sys-if.h"

/* Classes */
size_t
JSGCHeap::Allocator::extractSize(void *ptr)
{
/* if you use this Function, it cause Purify Memory ERROR!! */
#ifdef VX
#ifdef EWB_MEM_VX_FOR_JS
    return ((int *) ptr)[-3];
#else
    return ((int *) ptr)[-1] - 8;
#endif
#else
    return ((int *) ptr)[-2] & ~0x7;
#endif
}
size_t
JSGCHeap::Allocator::getRealdl_mallocSize(void *ptr)
{
#ifdef EWB_MEM_VX_FOR_JS
    return ((int *) ptr)[-3];
#else
/* this Funxtion is not use without "dl_malloc" on VX-Works */
    return ((int *) ptr)[-1];
#endif
}
void *
JSGCHeap::Allocator::memalign(JSContext* cx, size_t alignment, size_t size)
{
    if (bytes + size > (size_t) maxBytes-60000) { /* -60000 avoid to gc header can not allocate */ 
	return NULL;
    }
    void *ptr = runtime->localHeap.memalign(alignment, size);

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

void *
JSGCHeap::Allocator::malloc(JSContext* cx, size_t size)
{
#if 0    /* avoid to return null if gc header is allocated */
    if (bytes + size > (size_t) maxBytes) {
	return NULL;
    }
#endif
    void *ptr = runtime->localHeap.malloc(size);

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

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

    gcObj->finalize( cx );
}
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(cx, 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
    cx->exceptionHandler->throwEx(cx, cx->outOfMemory);
    /* not reached */
    return NULL;
}
void *
JSGCHeap::newObj(JSContext *cx, size_t size)
{
    void *ptr = malloc(cx, 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
    cx->exceptionHandler->throwEx(cx, 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
}
JSGCHeap::~JSGCHeap()
{
    freeAll();
    memset(top_index, 0, sizeof (top_index));
}

