/*
 * 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.
 */
#ifndef _JS_HEAP_H_
#define _JS_HEAP_H_

#include <stdlib.h>
#ifdef TARGET_OS_LINUX
#include <malloc.h>
#endif
#ifdef VX
#if !defined CONF_WPAD
 #include "ewb-mem.h"
#else
 #include "js-mem.h"
#endif
#endif

#if defined(SUNOS5) || defined(TARGET_OS_LINUX)
extern int jsGCHeapSize;
extern int jsByteCodeHeapSize;
extern int jsZoneHeapSize;

extern int jsBytecodeMemsize;
extern int jsBytecodeMemsizeMax;
extern int jsGCMemsize;
extern int jsZoneMemsize;
extern int jsZoneMemsizeMax;

static void showGCMemforSun();
#endif

/* Classes */
class JSHeap {
    public:
        void *memalign(size_t alignment, size_t size) {
#if defined(TARGET_OS_LINUX)
            return ::memalign(alignment, size);
#elif defined(SUNOS5)
            return (void *) ::memalign(alignment, size);
#elif defined(VX)
            return EwbMAlignedAlloc( size, alignment );
#else
            ->
#endif
        }
        void *malloc(size_t size) {
#if defined(TARGET_OS_LINUX)
            return ::malloc(size);
#elif defined(SUNOS5)
            return ::malloc(size);
#elif defined(VX)
            return EwbMalloc( size );
#else
            ->
#endif
        }
        void free(void *ptr) {
#if defined(SUNOS5)
            ::free(ptr);
#elif defined(TARGET_OS_LINUX)
            ::free(ptr);
#elif defined(VX)
            if( ptr != NULL ) EwbMFree( ptr );
#else
            ->
#endif
        }
} ;


/* 2004.04.22 ichino */
class ByteCodeHeap {
    public:
        void *memalign(size_t alignment, size_t size) {
#if defined(TARGET_OS_LINUX)
            return ::memalign(alignment, size);
#elif defined(SUNOS5)
            if(jsByteCodeHeapSize <= jsBytecodeMemsize + (int)size){
                return 0;
            }
            void *mem_tmp = ::memalign(alignment, size);
            char* ptr_t = (char*)mem_tmp;
            ptr_t -= 8;
            int *num = (int*)ptr_t;
            int num_t = *num;
            jsBytecodeMemsize += num_t;
            if(jsBytecodeMemsize > jsBytecodeMemsizeMax){
              jsBytecodeMemsizeMax = jsBytecodeMemsize;
            }

            return mem_tmp;
#elif defined(VX)
            return ByteCodeMAlignedAlloc( size, alignment );
#else
            ->
#endif
        }
        void *malloc(size_t size) {
#if defined(TARGET_OS_LINUX)
            return ::malloc(size);
#elif defined(SUNOS5)
            if(jsByteCodeHeapSize <= jsBytecodeMemsize + (int)size){
                return 0;
            }
            void *mem_tmp =  ::malloc(size);
            char* ptr_t = (char*)mem_tmp;
            ptr_t -= 8;
            int *num = (int*)ptr_t;
            int num_t = *num;
            jsBytecodeMemsize += num_t;
            if(jsBytecodeMemsize > jsBytecodeMemsizeMax){
              jsBytecodeMemsizeMax = jsBytecodeMemsize;
            }

            return mem_tmp;

#elif defined(VX)
            return ByteCodeMalloc( size );
#else
            ->
#endif
        }
        void free(void *ptr) {
#if defined(SUNOS5)
            char* ptr_t = (char*)ptr;
            ptr_t -= 8;
            int *num = (int*)ptr_t;
            int num_t = *num;
            jsBytecodeMemsize -= num_t;

            ::free(ptr);
#elif defined(TARGET_OS_LINUX)
            ::free(ptr);
#elif defined(VX)
            if( ptr != NULL ) ByteCodeMFree( ptr );
#else
            ->
#endif
        }
#if defined(SUNOS5)
        static void show() {
          printf("jsBytecodeMemsize:%d\n",jsBytecodeMemsize);
        }
#endif

} ;

/* 2004.02.09 ichino JSLocalHeap is memory allocate class for JS GC */
class JSLocalHeap {
    public:
        void *memalign(size_t alignment, size_t size) {
#if defined(TARGET_OS_LINUX)
            if (size <= 0) {
                errno = 0; /*< This is a successful case. */
                return NULL;
            }
            if ((alignment < sizeof(void*)) || /*< alignment was not a multiple of sizeof(void*). */
                ((alignment & (alignment - 1)) != 0) /*< alignment was not a power of 2. */
                ) {
                errno = EINVAL;
                return NULL;
            }

            char *p = NULL;
            void *org = NULL;
            const size_t header_size = sizeof(void*) + sizeof(size_t);
            const size_t total_size = size + ((header_size + (alignment - 1)) / alignment) * alignment;

            if ((org = ::memalign(alignment, total_size)) == NULL) {
                return NULL;
            }

            p = (char*)org;

            /** Step over the part which will be used to contain header info. */
            p += header_size;

            /** Move to the position where the correct alignment is. */
            if (((size_t)p) % alignment) {
                p += (alignment - (((size_t)p) % alignment));
            }

            /** Step back the position where is the starting of the header info. */
            p -= header_size;

            /** Store the original location returned by memalign. */
            memcpy(p, &org, sizeof(void*)); p += sizeof(void*);

            /** Store the requested size of the allocated memory. */
            ((size_t*)p)[0] = size; p += sizeof(size_t);

            return p;
#elif defined(SUNOS5)
            if(jsGCHeapSize <= jsGCMemsize + (int)size){
                return 0;
            }
            void *mem_tmp = ::memalign(alignment, size);
            char* ptr_t = (char*)mem_tmp;
            ptr_t -= 8;
            int *num = (int*)ptr_t;
            int num_t = *num;
            jsGCMemsize += num_t;

            return mem_tmp;
#elif defined(VX)
            return JsMAlignedAlloc( size, alignment );
#else
            ->
#endif
        }
        void *malloc(size_t size) {
#if defined(TARGET_OS_LINUX)
            if (size <= 0) {
                errno = 0; /*< This is a successful case. */
                return NULL;
            }

            char *p = NULL;
            void *org = NULL;
            const size_t header_size = sizeof(void*) + sizeof(size_t);

            if ((org = ::malloc(size + header_size)) == NULL) {
                return NULL;
            }

            p = (char*)org;

            /** Store the original location returned by memalign. */
            memcpy(p, &org, sizeof(void*)); p += sizeof(void*);

            /** Store the requested size of the allocated memory. */
            ((size_t*)p)[0] = size; p += sizeof(size_t);

            return p;
#elif defined(SUNOS5)
            if(jsGCHeapSize <= jsGCMemsize + (int)size){
                return 0;
            }
            void *mem_tmp =  ::malloc(size);
            char* ptr_t = (char*)mem_tmp;
            ptr_t -= 8;
            int *num = (int*)ptr_t;
            int num_t = *num;
            jsGCMemsize += num_t;

            return mem_tmp;
#elif defined(VX)
            return JsMalloc( size );
#else
            ->
#endif
        }
        void free(void *ptr) {
#if defined(SUNOS5)
            char* ptr_t = (char*)ptr;
            ptr_t -= 8;
            int *num = (int*)ptr_t;
            int num_t = *num;
            jsGCMemsize -= num_t;

            ::free(ptr);
#elif defined(TARGET_OS_LINUX)
            if (ptr) {
                void *real_ptr = NULL;
                char *p = (char*)ptr;

                /** Restore the pointer pointed to the header info. */
                p -= (sizeof(void*) + sizeof(size_t));

                /** Restore the original pointer returned by ::malloc or ::memalign. */
                memcpy(&real_ptr, p, sizeof(void*));

                /** Free the original pointer returned by ::malloc or ::memalign. */
                ::free(real_ptr);
            }
#elif defined(VX)
            if( ptr != NULL ) JsMFree( ptr );
#else
            ->
#endif
        }
};

/* 2004.02.23 ichino */
class JSZoneLocalHeap {
    public:
        void *memalign(size_t alignment, size_t size) {
#if defined(TARGET_OS_LINUX)
            return ::memalign(alignment, size);
#elif defined(SUNOS5)
            if(jsZoneHeapSize <= jsZoneMemsize + (int)size){
                return 0;
            }
            void *mem_tmp = ::memalign(alignment, size);
            char* ptr_t = (char*)mem_tmp;
            ptr_t -= 8;
            int *num = (int*)ptr_t;
            int num_t = *num;
            jsZoneMemsize += num_t;
            if(jsZoneMemsize > jsZoneMemsizeMax){
              jsZoneMemsizeMax = jsZoneMemsize;
            }
            return mem_tmp;
#elif defined(VX)
            return JsZoneMAlignedAlloc( size, alignment );
#else
            ->
#endif
        }
        void *malloc(size_t size) {
#if defined(TARGET_OS_LINUX)
            return ::malloc(size);
#elif defined(SUNOS5)
            if(jsZoneHeapSize <= jsZoneMemsize + (int)size){
                return 0;
            }
            void *mem_tmp =  ::malloc(size);
            char* ptr_t = (char*)mem_tmp;
            ptr_t -= 8;
            int *num = (int*)ptr_t;
            int num_t = *num;
            jsZoneMemsize += num_t;
            if(jsZoneMemsize > jsZoneMemsizeMax){
              jsZoneMemsizeMax = jsZoneMemsize;
            }

            return mem_tmp;
#elif defined(VX)
            return JsZoneMalloc( size );
#else
            ->
#endif
        }
        void free(void *ptr) {
#if defined(SUNOS5)
            char* ptr_t = (char*)ptr;
            ptr_t -= 8;
            int *num = (int*)ptr_t;
            int num_t = *num;
            jsZoneMemsize -= num_t;

            ::free(ptr);
#elif defined(TARGET_OS_LINUX)
            ::free(ptr);
#elif defined(VX)
            if( ptr != NULL ) JsZoneMFree( ptr );
#else
            ->
#endif
        }
};

#if defined(SUNOS5) || defined(TARGET_OS_LINUX)
static void
showGCMemforSun(){
        //Show JS object partition size.
        printf("### JS object partition ###\n");
        printf("Partition size   = %10u\n",
               (unsigned int)jsGCHeapSize);

        //Show JBytecodeS object partition size.
        printf("### JS bytecode partition ###\n");
        printf("Partition size   = %10u\n",
               (unsigned int)jsByteCodeHeapSize);
        printf("Now Used        = %10u\n",
               (unsigned int)jsBytecodeMemsize);
        printf("MAX Used        = %10u\n",
               (unsigned int)jsBytecodeMemsizeMax);

        printf("MAX Used / Partition size = %3.1f%%\n",
               (((double)jsBytecodeMemsizeMax/(double)jsByteCodeHeapSize)*100));


        //Show compile partition size.
        printf("### JS compile partition ###\n");
        printf("Partition size   = %10u\n",
               (unsigned int)jsZoneHeapSize);
        printf("Now Used        = %10u\n",
               (unsigned int)jsZoneMemsize);
        printf("MAX Used        = %10u\n",
               (unsigned int)jsZoneMemsizeMax);

        printf("MAX Used / Partition size = %3.1f%%\n",
               (((double)jsZoneMemsizeMax/(double)jsZoneHeapSize)*100));

}

static void
changeGCMemSize(int gc, int bytecode, int compile){
  printf("### Enter JS memory size. ###\n");
  jsGCHeapSize = gc;
  jsByteCodeHeapSize = bytecode;
  jsZoneHeapSize = compile;
  printf("### JS memory size changed. ###\n");
  showGCMemforSun();
}
#endif


#endif /* _JS_HEAP_H_ */

