/*
 * 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.
 */

/**
 * classes.h
 * Contains conterparts of special classes as C structs.
 */

#ifndef _CLASSES_H
#define _CLASSES_H

#include "types.h"

#define GC_MASK         0xc000
#define GC_SHIFT        14

#define LEN_AHARRAY     0x3e
#define LEN_BIGARRAY    0x3d

#define get_monitor_count(SYNC_)  ((SYNC_)->monitorCount)
#define is_gc(OBJ_)              ((OBJ_)->flags.mark)

// Double-check these data structures with the
// Java declaration of each corresponding class.
/**
 * Object header used for all objects types.
 * The mark field is used by the garbage collector.
 * Arrays with more then 60 elements have the length field set to LEN_BIGARRAY
 * Arrays with less than 60 elements have the actual length set in length.
 * Free memory has a class of T_FREE and either a 0 length or LEN_BIGARRAY
 * Big arrays have the actual length stored in the length field of the
 * BigArray header.
 */
typedef struct _flags
{
    byte is_array:1;
    uint16_t bits:13;
    /*
     * interpretation of bits:13 for array object
     * byte class :7;
     * byte length:6;
     */
    byte mark:2;
} objFlags;

_Static_assert(sizeof(objFlags) == 2, "sizeof(objFlags) == 2");

/**
 * Synchronization state.
 */
typedef struct
{
    byte monitorCount : 7;
    byte hasWaiters : 1;
    byte threadId;
} objSync;

/**
 * Object class native structure
 */
typedef struct S_Object
{
    objFlags flags;
    objSync sync;
} Object;

typedef struct S_BigArray
{
    Object hdr;
    uint16_t length;
    int16_t offset;
} BigArray;

static inline nvm_class_index_t nvm_object_class_index(Object* object)
{
    return object->flags.is_array ? object->flags.bits & (uint16_t)0x7F : object->flags.bits;
}

static inline nvm_array_size_t nvm_object_array_size(Object* object)
{
    return object->flags.bits >> 7;
}

extern void nvm_object_array_size_set(Object* object, byte size);

extern void nvm_object_init(Object* object, nvm_class_index_t class_index, _Bool is_array, byte size);

static inline _Bool nvm_object_is_array(Object* object)
{
    return object->flags.is_array;
}

extern _Bool nvm_object_is_array_std(Object* object);
extern _Bool nvm_object_is_array_big(Object* object);
extern _Bool nvm_object_is_array_ah(Object* object);

extern nvm_array_size_t nvm_array_size(Object* object);

/**
 * Thread class native structure
 */
typedef struct S_Thread
{
    Object _super;	     // Superclass object storage
    
    REFERENCE nextThread;      // Intrinsic circular list of threads
    REFERENCE waitingOn;       // Object who's monitor we want
    REFERENCE sync;             // Pointer to the sync data for the object
    TIMESTAMP sleepUntil;           // Time to wake up / also used as code buffer
    REFERENCE stackFrameArray; // Array of stack frames
    REFERENCE stackArray;      // The stack itself
    byte stackFrameIndex;      // Index of the current stack frame.
    byte monitorCount;         // Saved monitor depth for context switches
    byte threadId;             // Unique thread ID
    byte state;                // RUNNING, DEAD, etc.
    byte priority;             // The priority
    byte interruptState;       // INTERRUPT_CLEARED, INTERRUPT_REQUESTED, ...
    byte daemon;               // true == daemon thread
    byte reserved;
} Thread;

/**
 * String class native structure
 */
typedef struct S_String
{
    Object _super;
    REFERENCE characters;
} String;

typedef struct S_Throwable
{
    Object _super;
    
    REFERENCE stackTrace;
    REFERENCE msg;
} Throwable;

#endif
