/*
 * Copyright (C) 2018-2020 Western Digital Corporation or its affiliates
 * Copyright (C) 2017-2018 Wearable, Inc.
 * Copyright (C) 2000-2012 leJOS Contributors
 * Copyright (C) 2000 Jose H. Solorzano and TinyVM Contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 * 
 * This Source Code Form is “Incompatible With Secondary Licenses”,
 * as defined by the Mozilla Public License, v. 2.0.
 */

#ifndef MEMORY_H
#define MEMORY_H

#include "types.h"
#include "classes.h"
#include "state.h"

#include "language.h"

#define update_array(state, obj) {if((state)->gc_phase == GC_MARK && ((*(uint16_t *)(obj)) & GC_MASK) != GC_MASK) gc_update_array((state), (obj));}
#define update_object(state, obj) {if((state)->gc_phase == GC_MARK && ((*(uint16_t *)(obj)) & GC_MASK) != GC_MASK) gc_update_object((state), (obj));}
#define run_collector(state, check_timeout, force_compact) {if((state)->gc_phase != GC_IDLE) { gc_run_collector((state), (check_timeout), (force_compact)); }}

#define HEADER_SIZE (sizeof(Object))

#define fields_start(OBJ_)  ((byte *) (OBJ_) + HEADER_SIZE)
// Generic access to array data given an array object
#define array_start(OBJ_)   (nvm_object_is_array_std((Object *)(OBJ_)) ? (((byte *) (OBJ_)) + HEADER_SIZE) : (byte *)(((uint32_t *)(void*)(OBJ_)) + ((int)((BigArray *)(void*)(OBJ_))->offset)))
// Typed access to the data
#define jbyte_array(OBJ_)   ((JBYTE *) array_start(OBJ_))
#define word_array(OBJ_)    ((STACKWORD *) array_start(OBJ_))
#define ref_array(OBJ_)     ((REFERENCE*)(void*)array_start(OBJ_))
#define jint_array(OBJ_)    ((JINT*)(void*)array_start(OBJ_))
#define jshort_array(OBJ_)  ((JSHORT *) array_start(OBJ_))
#define jchar_array(OBJ_)   ((JCHAR *) array_start(OBJ_))
#define jlong_array(OBJ_)   ((JLONG *) array_start(OBJ_))
#define jfloat_array(OBJ_)  ((JFLOAT *) array_start(OBJ_))
// Following provide access to the array data given a pointer to the start
#define jbyte_array_ptr(PTR_)   ((JBYTE *) PTR_)
#define word_array_ptr(PTR_)    ((STACKWORD *) PTR_)
#define ref_array_ptr(PTR_)     ((REFERENCE *) PTR_)
#define jint_array_ptr(PTR_)    ((JINT *) PTR_)
#define jshort_array_ptr(PTR_)  ((JSHORT *) PTR_)
#define jchar_array_ptr(PTR_)   ((JCHAR *) PTR_)
#define jlong_array_ptr(PTR_)   ((JLONG *) PTR_)
#define jfloat_array_ptr(PTR_)  ((JFLOAT *) PTR_)

#define get_array_element_ptr(ARR_,ESIZE_,IDX_) (array_start((ARR_)) + (IDX_) * (ESIZE_))

#define protect_obj(OBJ) (((Object *)OBJ)->sync.monitorCount++)
#define unprotect_obj(OBJ) (((Object *)OBJ)->sync.monitorCount--)

void memory_init(nvm_state_t* pState);
void memory_add_region (nvm_state_t* pState, byte *region, byte *end, size_t array_heap_size);

Object *new_object_checked  (nvm_state_t* pState, nvm_class_index_t class_index, const byte *btAddr);
Object *new_object_for_class(nvm_state_t* pState, nvm_class_index_t class_index);
Object *new_single_array    (nvm_state_t* pState, nvm_class_index_t class_index, JINT length, boolean force_obj_heap);
Object *new_multi_array     (nvm_state_t* pState, nvm_class_index_t class_index, byte reqDimensions, STACKWORD *numElemPtr);
int init_stacks(nvm_state_t* pState, Thread *thread);
void free_stacks(nvm_state_t* pState, Thread *thread);
int expand_call_stack(nvm_state_t* pState, Thread *thread);
int expand_value_stack(nvm_state_t* pState, Thread *thread, int minSize);
Object *new_string(nvm_state_t* pState, ConstantRecord *constantRecord);
Object *new_string_from_cstr(nvm_state_t* pState, const char *cstr);
int arraycopy(nvm_state_t* pState, Object *src, int srcOff, Object *dst, int dstOff, int len);
STACKWORD get_word_4_swp(const byte *ptr);
void store_word_ns (byte *ptr, int typ, STACKWORD aWord);
STACKWORD get_word_ns(const byte *ptr, int typ);
STACKWORD get_word_4_ns(const byte *ptr);
int getHeapSize(nvm_state_t *);
int getHeapFree(nvm_state_t *);
int garbage_collect(nvm_state_t* pState);
void wait_garbage_collect(nvm_state_t* pState, boolean release_locks, boolean force_full);
Object *clone(nvm_state_t* pState, Object *old);

void gc_update_array(nvm_state_t* pState, Object *obj);
void gc_update_object(nvm_state_t* pState, Object *obj);
void gc_run_collector(nvm_state_t* pState, boolean timeout, boolean force_compact);

#endif



