Refactor literal-storage to not use C++ features
JerryScript-DCO-1.0-Signed-off-by: Roland Takacs rtakacs.u-szeged@partner.samsung.com
This commit is contained in:
@@ -0,0 +1,395 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015 University of Szeged
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "rcs-allocator.h"
|
||||
#include "rcs-records.h"
|
||||
|
||||
/**
|
||||
* Assert that recordset state is correct.
|
||||
*/
|
||||
static void
|
||||
rcs_assert_state_is_correct (rcs_record_set_t *rec_set_p __attr_unused___) /**< recordset */
|
||||
{
|
||||
#ifndef JERRY_DISABLE_HEAVY_DEBUG
|
||||
size_t node_size_sum = 0;
|
||||
size_t record_size_sum = 0;
|
||||
|
||||
rcs_record_t *last_record_p = NULL;
|
||||
rcs_record_t *rec_p;
|
||||
rcs_record_t *next_rec_p;
|
||||
|
||||
for (rec_p = rcs_record_get_first (rec_set_p);
|
||||
rec_p != NULL;
|
||||
last_record_p = rec_p, rec_p = next_rec_p)
|
||||
{
|
||||
JERRY_ASSERT (rcs_record_get_size (rec_p) > 0);
|
||||
record_size_sum += rcs_record_get_size (rec_p);
|
||||
|
||||
rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (rec_p);
|
||||
next_rec_p = rcs_record_get_next (rec_set_p, rec_p);
|
||||
rcs_chunked_list_t::node_t *next_node_p = NULL;
|
||||
|
||||
if (next_rec_p != NULL)
|
||||
{
|
||||
next_node_p = rec_set_p->get_node_from_pointer (next_rec_p);
|
||||
}
|
||||
|
||||
while (node_p != next_node_p)
|
||||
{
|
||||
node_p = rec_set_p->get_next (node_p);
|
||||
node_size_sum += rcs_get_node_data_space_size ();
|
||||
}
|
||||
}
|
||||
|
||||
JERRY_ASSERT (node_size_sum == record_size_sum);
|
||||
|
||||
record_size_sum = 0;
|
||||
|
||||
for (rec_p = last_record_p;
|
||||
rec_p != NULL;
|
||||
rec_p = rcs_record_get_prev (rec_set_p, rec_p))
|
||||
{
|
||||
record_size_sum += rcs_record_get_size (rec_p);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (node_size_sum == record_size_sum);
|
||||
#endif /* !JERRY_DISABLE_HEAVY_DEBUG */
|
||||
} /* rcs_assert_state_is_correct */
|
||||
|
||||
/**
|
||||
* Initialize specified record as free record.
|
||||
*/
|
||||
static void
|
||||
rcs_init_free_record (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_t *rec_p, /**< record to init as free record */
|
||||
rcs_record_t *prev_rec_p, /**< previous record (or NULL) */
|
||||
size_t size) /**< size, including header */
|
||||
{
|
||||
rcs_record_set_type (rec_p, RCS_RECORD_TYPE_FREE);
|
||||
rcs_record_set_prev (rec_set_p, rec_p, prev_rec_p);
|
||||
rcs_record_set_size (rec_p, size);
|
||||
} /* rcs_init_free_record */
|
||||
|
||||
/**
|
||||
* Check the alignment of the record.
|
||||
*/
|
||||
void
|
||||
rcs_check_record_alignment (rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
JERRY_ASSERT (rec_p != NULL);
|
||||
|
||||
uintptr_t ptr = (uintptr_t) rec_p;
|
||||
|
||||
JERRY_ASSERT (JERRY_ALIGNUP (ptr, RCS_DYN_STORAGE_LENGTH_UNIT) == ptr);
|
||||
} /* rcs_check_record_alignment */
|
||||
|
||||
/**
|
||||
* Get size of a node's data space.
|
||||
*
|
||||
* @return size
|
||||
*/
|
||||
size_t
|
||||
rcs_get_node_data_space_size (void)
|
||||
{
|
||||
return JERRY_ALIGNDOWN (rcs_chunked_list_t::get_node_data_space_size (), RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
} /* rcs_get_node_data_space_size */
|
||||
|
||||
/**
|
||||
* Get the node's data space.
|
||||
*
|
||||
* @return pointer to beginning of the node's data space
|
||||
*/
|
||||
uint8_t *
|
||||
rcs_get_node_data_space (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_chunked_list_t::node_t *node_p) /**< the node */
|
||||
{
|
||||
uintptr_t unaligned_data_space_start = (uintptr_t) rec_set_p->get_node_data_space (node_p);
|
||||
uintptr_t aligned_data_space_start = JERRY_ALIGNUP (unaligned_data_space_start, RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
|
||||
JERRY_ASSERT (unaligned_data_space_start + rcs_chunked_list_t::get_node_data_space_size ()
|
||||
== aligned_data_space_start + rcs_record_set_t::get_node_data_space_size ());
|
||||
|
||||
return (uint8_t *) aligned_data_space_start;
|
||||
} /* rcs_get_node_data_space */
|
||||
|
||||
/**
|
||||
* Initialize record in specified place, and, if there is free space
|
||||
* before next record, initialize free record for the space.
|
||||
*/
|
||||
static void
|
||||
rcs_alloc_record_in_place (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_t *place_p, /**< where to initialize the record */
|
||||
rcs_record_t *next_record_p, /**< next allocated record */
|
||||
size_t free_size) /**< size of free part between the allocated record
|
||||
and the next allocated record */
|
||||
{
|
||||
const size_t node_data_space_size = rcs_get_node_data_space_size ();
|
||||
|
||||
if (next_record_p != NULL)
|
||||
{
|
||||
if (free_size == 0)
|
||||
{
|
||||
rcs_record_set_prev (rec_set_p, next_record_p, place_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (next_record_p);
|
||||
uint8_t *node_data_space_p = rcs_get_node_data_space (rec_set_p, node_p);
|
||||
|
||||
JERRY_ASSERT ((uint8_t *) next_record_p < node_data_space_p + node_data_space_size);
|
||||
|
||||
rcs_record_t *free_rec_p;
|
||||
|
||||
if ((uint8_t *) next_record_p >= node_data_space_p + free_size)
|
||||
{
|
||||
free_rec_p = (rcs_record_t *) ((uint8_t *) next_record_p - free_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size_passed_back = (size_t) ((uint8_t *) next_record_p - node_data_space_p);
|
||||
JERRY_ASSERT (size_passed_back < free_size && size_passed_back + node_data_space_size > free_size);
|
||||
|
||||
node_p = rec_set_p->get_prev (node_p);
|
||||
node_data_space_p = rcs_get_node_data_space (rec_set_p, node_p);
|
||||
|
||||
free_rec_p = (rcs_record_t *) (node_data_space_p + node_data_space_size - \
|
||||
(free_size - size_passed_back));
|
||||
}
|
||||
|
||||
rcs_init_free_record (rec_set_p, free_rec_p, place_p, free_size);
|
||||
}
|
||||
}
|
||||
else if (free_size != 0)
|
||||
{
|
||||
rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (place_p);
|
||||
JERRY_ASSERT (node_p != NULL);
|
||||
|
||||
rcs_chunked_list_t::node_t *next_node_p = rec_set_p->get_next (node_p);
|
||||
|
||||
while (next_node_p != NULL)
|
||||
{
|
||||
node_p = next_node_p;
|
||||
next_node_p = rec_set_p->get_next (node_p);
|
||||
}
|
||||
|
||||
uint8_t *node_data_space_p = rcs_get_node_data_space (rec_set_p, node_p);
|
||||
const size_t node_data_space_size = rcs_get_node_data_space_size ();
|
||||
|
||||
rcs_record_t *free_rec_p = (rcs_record_t *) (node_data_space_p + node_data_space_size - free_size);
|
||||
rcs_init_free_record (rec_set_p, free_rec_p, place_p, free_size);
|
||||
}
|
||||
} /* rcs_alloc_record_in_place */
|
||||
|
||||
/**
|
||||
* Allocate record of specified size.
|
||||
*
|
||||
* @return record identifier
|
||||
*/
|
||||
static rcs_record_t *
|
||||
rcs_alloc_space_for_record (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_t **out_prev_rec_p, /**< out: pointer to record, previous to the allocated,
|
||||
* or NULL if the allocated record is the first */
|
||||
size_t bytes) /**< size */
|
||||
{
|
||||
rcs_assert_state_is_correct (rec_set_p);
|
||||
|
||||
JERRY_ASSERT (JERRY_ALIGNUP (bytes, RCS_DYN_STORAGE_LENGTH_UNIT) == bytes);
|
||||
JERRY_ASSERT (out_prev_rec_p != NULL);
|
||||
|
||||
rcs_record_t *rec_p = NULL;
|
||||
*out_prev_rec_p = NULL;
|
||||
|
||||
const size_t node_data_space_size = rcs_get_node_data_space_size ();
|
||||
|
||||
for (rec_p = rcs_record_get_first (rec_set_p);
|
||||
rec_p != NULL;
|
||||
*out_prev_rec_p = rec_p, rec_p = rcs_record_get_next (rec_set_p, rec_p))
|
||||
{
|
||||
if (RCS_RECORD_IS_FREE (rec_p))
|
||||
{
|
||||
rcs_record_t *next_rec_p = rcs_record_get_next (rec_set_p, rec_p);
|
||||
size_t record_size = rcs_record_get_size (rec_p);
|
||||
|
||||
if (record_size >= bytes)
|
||||
{
|
||||
/* Record size is sufficient. */
|
||||
rcs_alloc_record_in_place (rec_set_p, rec_p, next_rec_p, record_size - bytes);
|
||||
return rec_p;
|
||||
}
|
||||
|
||||
rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (rec_p);
|
||||
uint8_t *node_data_space_p = rcs_get_node_data_space (rec_set_p, node_p);
|
||||
uint8_t *node_data_space_end_p = node_data_space_p + node_data_space_size;
|
||||
uint8_t *rec_space_p = (uint8_t *) rec_p;
|
||||
|
||||
if (rec_space_p + record_size >= node_data_space_end_p)
|
||||
{
|
||||
/* Record lies up to end of node's data space size,
|
||||
* thus it can be extended up to necessary size. */
|
||||
while (record_size < bytes)
|
||||
{
|
||||
node_p = rec_set_p->insert_new (node_p);
|
||||
record_size += node_data_space_size;
|
||||
}
|
||||
|
||||
rcs_alloc_record_in_place (rec_set_p, rec_p, next_rec_p, record_size - bytes);
|
||||
return rec_p;
|
||||
}
|
||||
|
||||
if (next_rec_p == NULL)
|
||||
{
|
||||
/* There are no more records in the storage,
|
||||
* so we should append a new record. */
|
||||
break;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (!RCS_RECORD_IS_FREE (rec_p));
|
||||
}
|
||||
}
|
||||
|
||||
/* Free record of sufficient size was not found. */
|
||||
rcs_chunked_list_t::node_t *node_p = rec_set_p->append_new ();
|
||||
rcs_record_t *new_rec_p = (rcs_record_t *) rcs_get_node_data_space (rec_set_p, node_p);
|
||||
|
||||
size_t allocated_size = node_data_space_size;
|
||||
|
||||
while (allocated_size < bytes)
|
||||
{
|
||||
allocated_size += node_data_space_size;
|
||||
rec_set_p->append_new ();
|
||||
}
|
||||
|
||||
rcs_alloc_record_in_place (rec_set_p, new_rec_p, NULL, allocated_size - bytes);
|
||||
|
||||
return new_rec_p;
|
||||
} /* rcs_alloc_space_for_record */
|
||||
|
||||
/**
|
||||
* Allocate and initialize a new record.
|
||||
*
|
||||
* @return pointer to the new record
|
||||
*/
|
||||
rcs_record_t *
|
||||
rcs_alloc_record (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_type_t type, /**< type for the new record */
|
||||
size_t size) /**< allocation size */
|
||||
{
|
||||
JERRY_ASSERT (type >= RCS_RECORD_TYPE_FIRST && type <= RCS_RECORD_TYPE_LAST);
|
||||
|
||||
rcs_record_t *prev_rec_p;
|
||||
rcs_record_t *rec_p = (rcs_record_t *) rcs_alloc_space_for_record (rec_set_p, &prev_rec_p, size);
|
||||
|
||||
rcs_record_set_type (rec_p, type);
|
||||
rcs_record_set_size (rec_p, size);
|
||||
rcs_record_set_prev (rec_set_p, rec_p, prev_rec_p);
|
||||
|
||||
rcs_assert_state_is_correct (rec_set_p);
|
||||
|
||||
return rec_p;
|
||||
} /* alloc_record */
|
||||
|
||||
/**
|
||||
* Free the specified record.
|
||||
*/
|
||||
void
|
||||
rcs_free_record (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_t *record_p) /**< record to free */
|
||||
{
|
||||
JERRY_ASSERT (record_p != NULL);
|
||||
|
||||
rcs_assert_state_is_correct (rec_set_p);
|
||||
|
||||
rcs_record_t *prev_rec_p = rcs_record_get_prev (rec_set_p, record_p);
|
||||
|
||||
rcs_init_free_record (rec_set_p, record_p, prev_rec_p, rcs_record_get_size (record_p));
|
||||
|
||||
/* Merge adjacent free records, if there are any,
|
||||
* and free nodes of chunked list that became unused. */
|
||||
rcs_record_t *rec_from_p = record_p;
|
||||
rcs_record_t *rec_to_p = rcs_record_get_next (rec_set_p, record_p);
|
||||
|
||||
if (prev_rec_p != NULL && RCS_RECORD_IS_FREE (prev_rec_p))
|
||||
{
|
||||
rec_from_p = prev_rec_p;
|
||||
prev_rec_p = rcs_record_get_prev (rec_set_p, rec_from_p);
|
||||
}
|
||||
|
||||
if (rec_to_p != NULL && RCS_RECORD_IS_FREE (rec_to_p))
|
||||
{
|
||||
rec_to_p = rcs_record_get_next (rec_set_p, rec_to_p);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (rec_from_p != NULL && RCS_RECORD_IS_FREE (rec_from_p));
|
||||
JERRY_ASSERT (rec_to_p == NULL || !RCS_RECORD_IS_FREE (rec_to_p));
|
||||
|
||||
rcs_chunked_list_t::node_t *node_from_p = rec_set_p->get_node_from_pointer (rec_from_p);
|
||||
rcs_chunked_list_t::node_t *node_to_p = NULL;
|
||||
|
||||
if (rec_to_p != NULL)
|
||||
{
|
||||
node_to_p = rec_set_p->get_node_from_pointer (rec_to_p);
|
||||
}
|
||||
|
||||
const size_t node_data_space_size = rcs_get_node_data_space_size ();
|
||||
|
||||
uint8_t *rec_from_beg_p = (uint8_t *) rec_from_p;
|
||||
uint8_t *rec_to_beg_p = (uint8_t *) rec_to_p;
|
||||
size_t free_size;
|
||||
|
||||
if (node_from_p == node_to_p)
|
||||
{
|
||||
JERRY_ASSERT (rec_from_beg_p + rcs_record_get_size (rec_from_p) <= rec_to_beg_p);
|
||||
free_size = (size_t) (rec_to_beg_p - rec_from_beg_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
rcs_chunked_list_t::node_t *iter_node_p;
|
||||
rcs_chunked_list_t::node_t *iter_next_node_p;
|
||||
|
||||
for (iter_node_p = rec_set_p->get_next (node_from_p);
|
||||
iter_node_p != node_to_p;
|
||||
iter_node_p = iter_next_node_p)
|
||||
{
|
||||
iter_next_node_p = rec_set_p->get_next (iter_node_p);
|
||||
rec_set_p->remove (iter_node_p);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (rec_set_p->get_next (node_from_p) == node_to_p);
|
||||
|
||||
size_t node_from_space = (size_t) (rcs_get_node_data_space (rec_set_p, node_from_p) \
|
||||
+ node_data_space_size - rec_from_beg_p);
|
||||
size_t node_to_space = (size_t) (node_to_p != NULL ? \
|
||||
(rec_to_beg_p - rcs_get_node_data_space (rec_set_p, node_to_p)) : 0);
|
||||
|
||||
free_size = node_from_space + node_to_space;
|
||||
}
|
||||
|
||||
rcs_init_free_record (rec_set_p, rec_from_p, prev_rec_p, free_size);
|
||||
|
||||
if (rec_to_p != NULL)
|
||||
{
|
||||
rcs_record_set_prev (rec_set_p, rec_to_p, rec_from_p);
|
||||
}
|
||||
else if (prev_rec_p == NULL)
|
||||
{
|
||||
rec_set_p->remove (node_from_p);
|
||||
|
||||
JERRY_ASSERT (node_to_p == NULL);
|
||||
JERRY_ASSERT (rec_set_p->get_first () == NULL);
|
||||
}
|
||||
|
||||
rcs_assert_state_is_correct (rec_set_p);
|
||||
} /* rcs_free_record */
|
||||
@@ -0,0 +1,28 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015 University of Szeged
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef RCS_ALLOCATOR_H
|
||||
#define RCS_ALLOCATOR_H
|
||||
|
||||
#include "rcs-globals.h"
|
||||
|
||||
extern void rcs_check_record_alignment (rcs_record_t *);
|
||||
extern void rcs_free_record (rcs_record_set_t *, rcs_record_t *);
|
||||
extern size_t rcs_get_node_data_space_size (void);
|
||||
extern uint8_t *rcs_get_node_data_space (rcs_record_set_t *, rcs_chunked_list_t::node_t *);
|
||||
extern rcs_record_t *rcs_alloc_record (rcs_record_set_t *, rcs_record_type_t, size_t);
|
||||
|
||||
#endif /* !RCS_ALLOCATOR_H */
|
||||
@@ -0,0 +1,104 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015 University of Szeged
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "rcs-cpointer.h"
|
||||
#include "jrt-bit-fields.h"
|
||||
|
||||
/**
|
||||
* Compress pointer to extended compressed pointer.
|
||||
*
|
||||
* @return dynamic storage-specific extended compressed pointer
|
||||
*/
|
||||
rcs_cpointer_t
|
||||
rcs_cpointer_compress (rcs_record_t *pointer) /**< pointer to compress */
|
||||
{
|
||||
rcs_cpointer_t cpointer;
|
||||
cpointer.packed_value = 0;
|
||||
|
||||
uintptr_t base_pointer = JERRY_ALIGNDOWN ((uintptr_t) pointer, MEM_ALIGNMENT);
|
||||
|
||||
if ((void *) base_pointer == NULL)
|
||||
{
|
||||
cpointer.value.base_cp = MEM_CP_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpointer.value.base_cp = mem_compress_pointer ((void *) base_pointer) & MEM_CP_MASK;
|
||||
}
|
||||
|
||||
#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG
|
||||
/*
|
||||
* If alignment of a unit in recordset storage is less than required by MEM_ALIGNMENT_LOG,
|
||||
* then mem_cpointer_t can't store pointer to the unit, and so, rcs_cpointer_t stores
|
||||
* mem_cpointer_t to block, aligned to MEM_ALIGNMENT, and also extension with difference
|
||||
* between positions of the MEM_ALIGNMENT-aligned block and the unit.
|
||||
*/
|
||||
uintptr_t diff = (uintptr_t) pointer - base_pointer;
|
||||
|
||||
JERRY_ASSERT (diff < MEM_ALIGNMENT);
|
||||
JERRY_ASSERT (jrt_extract_bit_field (diff, 0, RCS_DYN_STORAGE_LENGTH_UNIT_LOG) == 0);
|
||||
|
||||
uintptr_t ext_part = (uintptr_t) jrt_extract_bit_field (diff,
|
||||
RCS_DYN_STORAGE_LENGTH_UNIT_LOG,
|
||||
MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG);
|
||||
|
||||
cpointer.value.ext = ext_part & ((1ull << (MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG)) - 1);
|
||||
#endif /* MEM_ALIGNMENT > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */
|
||||
JERRY_ASSERT (rcs_cpointer_decompress (cpointer) == pointer);
|
||||
|
||||
return cpointer;
|
||||
} /* rcs_cpointer_compress */
|
||||
|
||||
/**
|
||||
* Decompress extended compressed pointer.
|
||||
*
|
||||
* @return decompressed pointer
|
||||
*/
|
||||
rcs_record_t *
|
||||
rcs_cpointer_decompress (rcs_cpointer_t compressed_pointer) /**< recordset-specific compressed pointer */
|
||||
{
|
||||
uint8_t *base_pointer = NULL;
|
||||
|
||||
if (compressed_pointer.value.base_cp != MEM_CP_NULL)
|
||||
{
|
||||
base_pointer = (uint8_t *) mem_decompress_pointer (compressed_pointer.value.base_cp);
|
||||
}
|
||||
|
||||
uintptr_t diff = 0;
|
||||
#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG
|
||||
/*
|
||||
* See also:
|
||||
* rcs_cpointer_compress
|
||||
*/
|
||||
|
||||
diff = (uintptr_t) compressed_pointer.value.ext << RCS_DYN_STORAGE_LENGTH_UNIT_LOG;
|
||||
#endif /* MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */
|
||||
rcs_record_t *rec_p = (rcs_record_t *) (base_pointer + diff);
|
||||
|
||||
return rec_p;
|
||||
} /* rcs_cpointer_decompress */
|
||||
|
||||
/**
|
||||
* Create NULL compressed pointer.
|
||||
*
|
||||
* @return NULL compressed pointer
|
||||
*/
|
||||
rcs_cpointer_t rcs_cpointer_null_cp (void)
|
||||
{
|
||||
rcs_cpointer_t cp;
|
||||
cp.packed_value = MEM_CP_NULL;
|
||||
return cp;
|
||||
} /* rcs_cpointer_null_cp */
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015 University of Szeged
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef RCS_CPOINTER_H
|
||||
#define RCS_CPOINTER_H
|
||||
|
||||
#include "rcs-globals.h"
|
||||
|
||||
#define RCS_CPOINTER_WIDTH (MEM_CP_WIDTH + MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG)
|
||||
|
||||
/**
|
||||
* Dynamic storage-specific extended compressed pointer
|
||||
*
|
||||
* Note:
|
||||
* the pointer can represent addresses aligned by RCS_DYN_STORAGE_LENGTH_UNIT,
|
||||
* while mem_cpointer_t can only represent addresses aligned by MEM_ALIGNMENT.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
mem_cpointer_t base_cp : MEM_CP_WIDTH; /**< pointer to base of addressed area */
|
||||
#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG
|
||||
uint16_t ext : (MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG); /**< extension of the basic
|
||||
* compressed pointer
|
||||
* used for more detailed
|
||||
* addressing */
|
||||
#endif /* MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */
|
||||
} value;
|
||||
uint16_t packed_value;
|
||||
};
|
||||
} rcs_cpointer_t;
|
||||
|
||||
extern rcs_cpointer_t rcs_cpointer_compress (rcs_record_t *);
|
||||
extern rcs_record_t *rcs_cpointer_decompress (rcs_cpointer_t);
|
||||
extern rcs_cpointer_t rcs_cpointer_null_cp ();
|
||||
|
||||
#endif /* !RCS_CPOINTER_H */
|
||||
@@ -0,0 +1,54 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015 University of Szeged
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef RCS_GLOBALS_H
|
||||
#define RCS_GLOBALS_H
|
||||
|
||||
#include "rcs-chunked-list.h"
|
||||
|
||||
/**
|
||||
* Represents the type of the record.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
RCS_RECORD_TYPE_FREE = 0, /**< Free record that marks an empty space. It doesn't hold any values. */
|
||||
RCS_RECORD_TYPE_CHARSET = 1, /**< Charset record that holds characters. */
|
||||
RCS_RECORD_TYPE_MAGIC_STR = 2, /**< Magic string record that holds a magic string id. */
|
||||
RCS_RECORD_TYPE_MAGIC_STR_EX = 3, /**< External magic string record that holds an extrernal magic string id. */
|
||||
RCS_RECORD_TYPE_NUMBER = 4 /**< Number record that holds a numeric value. */
|
||||
} rcs_record_type_t;
|
||||
|
||||
/**
|
||||
* Record type
|
||||
*/
|
||||
typedef uint8_t rcs_record_t;
|
||||
|
||||
/**
|
||||
* Recordset type
|
||||
*/
|
||||
typedef rcs_chunked_list_t rcs_record_set_t;
|
||||
|
||||
/**
|
||||
* Logarithm of a dynamic storage unit alignment
|
||||
*/
|
||||
#define RCS_DYN_STORAGE_LENGTH_UNIT_LOG (2u)
|
||||
|
||||
/**
|
||||
* Unit of length
|
||||
*/
|
||||
#define RCS_DYN_STORAGE_LENGTH_UNIT ((size_t) (1ull << RCS_DYN_STORAGE_LENGTH_UNIT_LOG))
|
||||
|
||||
#endif /* !RCS_GLOBALS_H */
|
||||
@@ -0,0 +1,214 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015 University of Szeged
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "rcs-iterator.h"
|
||||
#include "rcs-allocator.h"
|
||||
#include "rcs-records.h"
|
||||
|
||||
/**
|
||||
* Represents the memory access on the literal storage.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
RCS_ITERATOR_ACCESS_WRITE = 0, /**< Write 'size' bytes from 'data' buffer to the record. */
|
||||
RCS_ITERATOR_ACCESS_READ = 1, /**< Read 'size' bytes from the record and write to the 'data' buffer. */
|
||||
RCS_ITERATOR_ACCESS_SKIP = 2 /**< Increment current position so that 'size' bytes would be skipped. */
|
||||
} rcs_access_t;
|
||||
|
||||
/**
|
||||
* Create an iterator context.
|
||||
*
|
||||
* @return an initialized iterator context
|
||||
*/
|
||||
rcs_iterator_t
|
||||
rcs_iterator_create (rcs_record_set_t *recordset_p, /**< recordset */
|
||||
rcs_record_t *record_p) /**< start record */
|
||||
{
|
||||
rcs_iterator_t ctx;
|
||||
{
|
||||
ctx.recordset_p = recordset_p;
|
||||
ctx.record_start_p = record_p;
|
||||
|
||||
rcs_iterator_reset (&ctx);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
} /* rcs_iterator_create */
|
||||
|
||||
/**
|
||||
* Perform general access to the record
|
||||
*
|
||||
* Warning: This function is implemented in assumption that `size` is not more than `2 * node_data_space_size`.
|
||||
*/
|
||||
static void
|
||||
rcs_iterator_access (rcs_iterator_t *ctx_p, /**< iterator context */
|
||||
void *data, /**< iterator context */
|
||||
size_t size, /**< iterator context */
|
||||
rcs_access_t access_type) /**< access type */
|
||||
{
|
||||
const size_t node_data_space_size = rcs_get_node_data_space_size ();
|
||||
JERRY_ASSERT (2 * node_data_space_size >= size);
|
||||
const size_t record_size = rcs_record_get_size (ctx_p->record_start_p);
|
||||
|
||||
JERRY_ASSERT (!rcs_iterator_finished (ctx_p));
|
||||
|
||||
rcs_chunked_list_t::node_t *current_node_p = ctx_p->recordset_p->get_node_from_pointer (ctx_p->current_pos_p);
|
||||
uint8_t *current_node_data_space_p = rcs_get_node_data_space (ctx_p->recordset_p, current_node_p);
|
||||
size_t left_in_node = node_data_space_size - (size_t) (ctx_p->current_pos_p - current_node_data_space_p);
|
||||
|
||||
JERRY_ASSERT (ctx_p->current_offset + size <= record_size);
|
||||
|
||||
/*
|
||||
* Read the data and increase the current position pointer.
|
||||
*/
|
||||
if (left_in_node >= size)
|
||||
{
|
||||
/* all data is placed inside single node */
|
||||
if (access_type == RCS_ITERATOR_ACCESS_READ)
|
||||
{
|
||||
memcpy (data, ctx_p->current_pos_p, size);
|
||||
}
|
||||
else if (access_type == RCS_ITERATOR_ACCESS_WRITE)
|
||||
{
|
||||
memcpy (ctx_p->current_pos_p, data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (access_type == RCS_ITERATOR_ACCESS_SKIP);
|
||||
|
||||
if (left_in_node > size)
|
||||
{
|
||||
ctx_p->current_pos_p += size;
|
||||
}
|
||||
else if (ctx_p->current_offset + size < record_size)
|
||||
{
|
||||
current_node_p = ctx_p->recordset_p->get_next (current_node_p);
|
||||
JERRY_ASSERT (current_node_p);
|
||||
ctx_p->current_pos_p = rcs_get_node_data_space (ctx_p->recordset_p, current_node_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (ctx_p->current_offset + size == record_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Data is distributed between two nodes. */
|
||||
const size_t first_chunk_size = node_data_space_size - (size_t) (ctx_p->current_pos_p - current_node_data_space_p);
|
||||
|
||||
if (access_type == RCS_ITERATOR_ACCESS_READ)
|
||||
{
|
||||
memcpy (data, ctx_p->current_pos_p, first_chunk_size);
|
||||
}
|
||||
else if (access_type == RCS_ITERATOR_ACCESS_WRITE)
|
||||
{
|
||||
memcpy (ctx_p->current_pos_p, data, first_chunk_size);
|
||||
}
|
||||
|
||||
rcs_chunked_list_t::node_t *next_node_p = ctx_p->recordset_p->get_next (current_node_p);
|
||||
JERRY_ASSERT (next_node_p != NULL);
|
||||
uint8_t *next_node_data_space_p = rcs_get_node_data_space (ctx_p->recordset_p, next_node_p);
|
||||
|
||||
if (access_type == RCS_ITERATOR_ACCESS_READ)
|
||||
{
|
||||
memcpy ((uint8_t *)data + first_chunk_size, next_node_data_space_p, size - first_chunk_size);
|
||||
}
|
||||
else if (access_type == RCS_ITERATOR_ACCESS_WRITE)
|
||||
{
|
||||
memcpy (next_node_data_space_p, (uint8_t *)data + first_chunk_size, size - first_chunk_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (access_type == RCS_ITERATOR_ACCESS_SKIP);
|
||||
ctx_p->current_pos_p = next_node_data_space_p + size - first_chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we reached the end. */
|
||||
if (access_type == RCS_ITERATOR_ACCESS_SKIP)
|
||||
{
|
||||
ctx_p->current_offset += size;
|
||||
JERRY_ASSERT (ctx_p->current_offset <= record_size);
|
||||
|
||||
if (ctx_p->current_offset == record_size)
|
||||
{
|
||||
ctx_p->current_pos_p = NULL;
|
||||
ctx_p->current_offset = 0;
|
||||
}
|
||||
}
|
||||
} /* rcs_iterator_access */
|
||||
|
||||
/**
|
||||
* Read a value from the record.
|
||||
* After reading iterator doesn't change its position.
|
||||
*
|
||||
* @return read value
|
||||
*/
|
||||
void
|
||||
rcs_iterator_read (rcs_iterator_t *ctx_p, /**< iterator context */
|
||||
void *out_data, /**< value to read */
|
||||
size_t size) /**< size to read */
|
||||
{
|
||||
rcs_iterator_access (ctx_p, out_data, size, RCS_ITERATOR_ACCESS_READ);
|
||||
} /* rcs_iterator_read */
|
||||
|
||||
/**
|
||||
* Write a value to the record.
|
||||
* After writing, iterator doesn't change its position.
|
||||
*/
|
||||
void
|
||||
rcs_iterator_write (rcs_iterator_t *ctx_p, /**< iterator context */
|
||||
void *value, /**< value to write */
|
||||
size_t size) /**< size to write */
|
||||
{
|
||||
rcs_iterator_access (ctx_p, value, size, RCS_ITERATOR_ACCESS_WRITE);
|
||||
} /* rcs_iterator_write */
|
||||
|
||||
/**
|
||||
* Increment current position to skip 'size' bytes.
|
||||
*/
|
||||
void
|
||||
rcs_iterator_skip (rcs_iterator_t *ctx_p, /**< iterator context */
|
||||
size_t size) /**< size to skip */
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
rcs_iterator_access (ctx_p, NULL, size, RCS_ITERATOR_ACCESS_SKIP);
|
||||
}
|
||||
} /* rcs_iterator_skip */
|
||||
|
||||
/**
|
||||
* Reset the iterator, so that it points to the beginning of the record.
|
||||
*/
|
||||
void
|
||||
rcs_iterator_reset (rcs_iterator_t *ctx_p) /**< iterator context */
|
||||
{
|
||||
ctx_p->current_pos_p = ctx_p->record_start_p;
|
||||
ctx_p->current_offset = 0;
|
||||
} /* rcs_iterator_reset */
|
||||
|
||||
/**
|
||||
* Check if the end of the record was reached.
|
||||
*
|
||||
* @return true if the whole record was iterated
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
rcs_iterator_finished (rcs_iterator_t *ctx_p) /**< iterator context */
|
||||
{
|
||||
return ctx_p->current_pos_p == NULL;
|
||||
} /* rcs_iterator_finished */
|
||||
@@ -0,0 +1,42 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015 University of Szeged
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef RCS_ITERATOR_H
|
||||
#define RCS_ITERATOR_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
|
||||
/**
|
||||
* Represents a context for the iterator.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
rcs_record_set_t *recordset_p; /**< recordset, containing the records */
|
||||
rcs_record_t *record_start_p; /**< start of current record */
|
||||
uint8_t *current_pos_p; /**< pointer to current offset in current record */
|
||||
size_t current_offset; /**< current offset */
|
||||
} rcs_iterator_t;
|
||||
|
||||
extern rcs_iterator_t rcs_iterator_create (rcs_record_set_t *, rcs_record_t *);
|
||||
|
||||
extern void rcs_iterator_write (rcs_iterator_t *, void *, size_t);
|
||||
extern void rcs_iterator_read (rcs_iterator_t *, void *, size_t);
|
||||
extern void rcs_iterator_skip (rcs_iterator_t *, size_t);
|
||||
|
||||
extern void rcs_iterator_reset (rcs_iterator_t *);
|
||||
extern bool rcs_iterator_finished (rcs_iterator_t *);
|
||||
|
||||
#endif /* !RCS_ITERATOR_H */
|
||||
@@ -0,0 +1,636 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015 University of Szeged
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "rcs-records.h"
|
||||
|
||||
#include "rcs-allocator.h"
|
||||
#include "rcs-cpointer.h"
|
||||
#include "rcs-iterator.h"
|
||||
#include "jrt-bit-fields.h"
|
||||
|
||||
/**
|
||||
* Set value of the record's field with specified offset and width.
|
||||
*/
|
||||
static void
|
||||
rcs_record_set_field (rcs_record_t *rec_p, /**< record */
|
||||
uint32_t field_pos, /**< offset, in bits */
|
||||
uint32_t field_width, /**< width, in bits */
|
||||
size_t value) /**< 32-bit unsigned integer value */
|
||||
{
|
||||
rcs_check_record_alignment (rec_p);
|
||||
|
||||
JERRY_ASSERT (sizeof (uint32_t) <= RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
JERRY_ASSERT (field_pos + field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE);
|
||||
|
||||
uint32_t prev_value = *(uint32_t *) rec_p;
|
||||
*(uint32_t *) rec_p = (uint32_t) jrt_set_bit_field_value (prev_value, value, field_pos, field_width);
|
||||
} /* rcs_record_set_field */
|
||||
|
||||
/**
|
||||
* Set the record's type identifier.
|
||||
*/
|
||||
void
|
||||
rcs_record_set_type (rcs_record_t *rec_p, /**< record */
|
||||
rcs_record_type_t type) /**< record type */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_TYPE_IS_VALID (type));
|
||||
|
||||
rcs_record_set_field (rec_p, RCS_HEADER_TYPE_POS, RCS_HEADER_TYPE_WIDTH, type);
|
||||
} /* rcs_record_set_type */
|
||||
|
||||
/**
|
||||
* Set previous record for the records.
|
||||
*/
|
||||
void
|
||||
rcs_record_set_prev (rcs_record_set_t *rec_sec_p, /**< recordset */
|
||||
rcs_record_t *rec_p, /**< record */
|
||||
rcs_record_t *prev_p) /**< prev record */
|
||||
{
|
||||
uint8_t begin_pos;
|
||||
|
||||
switch (rcs_record_get_type (rec_p))
|
||||
{
|
||||
case RCS_RECORD_TYPE_CHARSET:
|
||||
{
|
||||
rcs_cpointer_t prev_cpointer = rcs_cpointer_compress (prev_p);
|
||||
rcs_iterator_t it_ctx = rcs_iterator_create (rec_sec_p, rec_p);
|
||||
|
||||
rcs_iterator_skip (&it_ctx, RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
rcs_iterator_write (&it_ctx, &prev_cpointer.packed_value, sizeof (uint16_t));
|
||||
|
||||
return;
|
||||
}
|
||||
case RCS_RECORD_TYPE_FREE:
|
||||
{
|
||||
begin_pos = RCS_FREE_HEADER_PREV_POS;
|
||||
break;
|
||||
}
|
||||
case RCS_RECORD_TYPE_MAGIC_STR:
|
||||
case RCS_RECORD_TYPE_MAGIC_STR_EX:
|
||||
{
|
||||
begin_pos = RCS_MAGIC_STR_HEADER_PREV_POS;
|
||||
break;
|
||||
}
|
||||
case RCS_RECORD_TYPE_NUMBER:
|
||||
{
|
||||
begin_pos = RCS_NUMBER_HEADER_PREV_POS;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
}
|
||||
}
|
||||
|
||||
rcs_cpointer_t cpointer = rcs_cpointer_compress (prev_p);
|
||||
rcs_record_set_field (rec_p, begin_pos, RCS_CPOINTER_WIDTH, cpointer.packed_value);
|
||||
} /* rcs_record_set_prev */
|
||||
|
||||
/**
|
||||
* Set size of the records.
|
||||
*/
|
||||
void
|
||||
rcs_record_set_size (rcs_record_t *rec_p, /**< recordset */
|
||||
size_t size) /**< record size */
|
||||
{
|
||||
rcs_record_type_t type = rcs_record_get_type (rec_p);
|
||||
|
||||
if (RCS_RECORD_TYPE_IS_CHARSET (type))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_ALIGNUP (size, RCS_DYN_STORAGE_LENGTH_UNIT) == size);
|
||||
|
||||
rcs_record_set_field (rec_p,
|
||||
RCS_CHARSET_HEADER_LENGTH_POS,
|
||||
RCS_CHARSET_HEADER_LENGTH_WIDTH,
|
||||
size >> RCS_DYN_STORAGE_LENGTH_UNIT_LOG);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RCS_RECORD_TYPE_IS_FREE (type))
|
||||
{
|
||||
JERRY_ASSERT (JERRY_ALIGNUP (size, RCS_DYN_STORAGE_LENGTH_UNIT) == size);
|
||||
|
||||
rcs_record_set_field (rec_p,
|
||||
RCS_FREE_HEADER_LENGTH_POS,
|
||||
RCS_FREE_HEADER_LENGTH_WIDTH,
|
||||
size >> RCS_DYN_STORAGE_LENGTH_UNIT_LOG);
|
||||
return;
|
||||
}
|
||||
|
||||
JERRY_ASSERT (rcs_record_get_size (rec_p) == size);
|
||||
} /* rcs_record_set_size */
|
||||
|
||||
/**
|
||||
* Set the count of the alignment bytes at the end of record.
|
||||
*/
|
||||
void
|
||||
rcs_record_set_alignment_bytes_count (rcs_record_t *rec_p, /**< record */
|
||||
size_t count) /**< align bytes */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p));
|
||||
|
||||
rcs_record_set_field (rec_p, RCS_CHARSET_HEADER_ALIGN_POS, RCS_CHARSET_HEADER_ALIGN_WIDTH, count);
|
||||
} /* rcs_record_set_align */
|
||||
|
||||
/**
|
||||
* Set the hash value of the record.
|
||||
*/
|
||||
void
|
||||
rcs_record_set_hash (rcs_record_t *rec_p, /**< record */
|
||||
lit_string_hash_t hash) /**< hash value */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p));
|
||||
|
||||
rcs_record_set_field (rec_p, RCS_CHARSET_HEADER_HASH_POS, RCS_CHARSET_HEADER_HASH_WIDTH, hash);
|
||||
} /* rcs_record_set_hash */
|
||||
|
||||
/**
|
||||
* Set the charset of the record.
|
||||
*/
|
||||
void
|
||||
rcs_record_set_charset (rcs_record_set_t *rec_set_p, /**< recordset containing the records */
|
||||
rcs_record_t *rec_p, /**< record */
|
||||
const lit_utf8_byte_t *str_p, /**< buffer containing characters to set */
|
||||
lit_utf8_size_t size) /**< size of the buffer in bytes */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p));
|
||||
JERRY_ASSERT (RCS_CHARSET_HEADER_SIZE + size
|
||||
== rcs_record_get_size (rec_p) - rcs_record_get_alignment_bytes_count (rec_p));
|
||||
|
||||
rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p);
|
||||
rcs_iterator_skip (&it_ctx, RCS_CHARSET_HEADER_SIZE);
|
||||
|
||||
lit_utf8_size_t str_len = rcs_record_get_length (rec_p);
|
||||
lit_utf8_size_t i;
|
||||
|
||||
for (i = 0; i < str_len; ++i)
|
||||
{
|
||||
rcs_iterator_write (&it_ctx, (void *)(str_p + i), sizeof (lit_utf8_byte_t));
|
||||
rcs_iterator_skip (&it_ctx, sizeof (lit_utf8_byte_t));
|
||||
}
|
||||
} /* rcs_record_set_charset */
|
||||
|
||||
/**
|
||||
* Set the magic string id of the record.
|
||||
*/
|
||||
void
|
||||
rcs_record_set_magic_str_id (rcs_record_t *rec_p, /**< record */
|
||||
lit_magic_string_id_t id) /**< magic string id */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_MAGIC_STR (rec_p));
|
||||
|
||||
rcs_record_set_field (rec_p, RCS_MAGIC_STR_HEADER_ID_POS, RCS_MAGIC_STR_HEADER_ID_WIDTH, id);
|
||||
} /* rcs_record_set_magic_str_id */
|
||||
|
||||
/**
|
||||
* Set the external magic string id of the record.
|
||||
*/
|
||||
void
|
||||
rcs_record_set_magic_str_ex_id (rcs_record_t *rec_p, /**< record */
|
||||
lit_magic_string_ex_id_t id) /**< external magic string id */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_MAGIC_STR_EX (rec_p));
|
||||
|
||||
rcs_record_set_field (rec_p, RCS_MAGIC_STR_HEADER_ID_POS, RCS_MAGIC_STR_HEADER_ID_WIDTH, id);
|
||||
} /* rcs_record_set_magic_str_ex_id */
|
||||
|
||||
/**
|
||||
* Get value of the record's field with specified offset and width.
|
||||
*
|
||||
* @return field's 32-bit unsigned integer value
|
||||
*/
|
||||
static uint32_t
|
||||
rcs_record_get_field (rcs_record_t *rec_p, /**< record */
|
||||
uint32_t field_pos, /**< offset, in bits */
|
||||
uint32_t field_width) /**< width, in bits */
|
||||
{
|
||||
rcs_check_record_alignment (rec_p);
|
||||
|
||||
JERRY_ASSERT (sizeof (uint32_t) <= RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
JERRY_ASSERT (field_pos + field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE);
|
||||
|
||||
uint32_t value = *(uint32_t *) rec_p;
|
||||
return (uint32_t) jrt_extract_bit_field (value, field_pos, field_width);
|
||||
} /* rcs_record_get_field */
|
||||
|
||||
/**
|
||||
* Get value of the record's pointer field with specified offset and width.
|
||||
*
|
||||
* @return pointer to record
|
||||
*/
|
||||
static rcs_record_t *
|
||||
rcs_record_get_pointer (rcs_record_t *rec_p, /**< record */
|
||||
uint32_t field_pos, /**< offset, in bits */
|
||||
uint32_t field_width) /**< width, in bits */
|
||||
{
|
||||
rcs_cpointer_t cpointer;
|
||||
|
||||
uint16_t value = (uint16_t) rcs_record_get_field (rec_p, field_pos, field_width);
|
||||
|
||||
JERRY_ASSERT (sizeof (cpointer) == sizeof (cpointer.value));
|
||||
JERRY_ASSERT (sizeof (value) == sizeof (cpointer.value));
|
||||
|
||||
cpointer.packed_value = value;
|
||||
|
||||
return rcs_cpointer_decompress (cpointer);
|
||||
} /* rcs_record_get_pointer */
|
||||
|
||||
/**
|
||||
* Get the record's type identifier.
|
||||
*
|
||||
* @return record type identifier
|
||||
*/
|
||||
rcs_record_type_t
|
||||
rcs_record_get_type (rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
JERRY_STATIC_ASSERT (sizeof (rcs_record_type_t) * JERRY_BITSINBYTE >= RCS_HEADER_TYPE_WIDTH);
|
||||
|
||||
return (rcs_record_type_t) rcs_record_get_field (rec_p, RCS_HEADER_TYPE_POS, RCS_HEADER_TYPE_WIDTH);
|
||||
} /* rcs_record_get_type */
|
||||
|
||||
/**
|
||||
* Get previous record for the records.
|
||||
*
|
||||
* @return previous record
|
||||
*/
|
||||
rcs_record_t *
|
||||
rcs_record_get_prev (rcs_record_set_t *rec_sec_p, /**< recordset */
|
||||
rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
uint8_t begin_pos;
|
||||
|
||||
switch (rcs_record_get_type (rec_p))
|
||||
{
|
||||
case RCS_RECORD_TYPE_CHARSET:
|
||||
{
|
||||
rcs_cpointer_t cpointer;
|
||||
rcs_iterator_t it_ctx = rcs_iterator_create (rec_sec_p, rec_p);
|
||||
|
||||
rcs_iterator_skip (&it_ctx, RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
rcs_iterator_read (&it_ctx, &cpointer.packed_value, sizeof (uint16_t));
|
||||
|
||||
return rcs_cpointer_decompress (cpointer);
|
||||
}
|
||||
case RCS_RECORD_TYPE_FREE:
|
||||
{
|
||||
begin_pos = RCS_FREE_HEADER_PREV_POS;
|
||||
break;
|
||||
}
|
||||
case RCS_RECORD_TYPE_MAGIC_STR:
|
||||
case RCS_RECORD_TYPE_MAGIC_STR_EX:
|
||||
{
|
||||
begin_pos = RCS_MAGIC_STR_HEADER_PREV_POS;
|
||||
break;
|
||||
}
|
||||
case RCS_RECORD_TYPE_NUMBER:
|
||||
{
|
||||
begin_pos = RCS_NUMBER_HEADER_PREV_POS;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
}
|
||||
}
|
||||
|
||||
return rcs_record_get_pointer (rec_p, begin_pos, RCS_CPOINTER_WIDTH);
|
||||
} /* rcs_record_get_prev */
|
||||
|
||||
/**
|
||||
* Get the count of the alignment bytes at the end of record.
|
||||
* These bytes are needed to align the record to RCS_DYN_STORAGE_ALIGNMENT.
|
||||
*
|
||||
* @return alignment bytes count
|
||||
*/
|
||||
size_t
|
||||
rcs_record_get_alignment_bytes_count (rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p));
|
||||
|
||||
return rcs_record_get_field (rec_p, RCS_CHARSET_HEADER_ALIGN_POS, RCS_CHARSET_HEADER_ALIGN_WIDTH);
|
||||
} /* rcs_record_get_alignment_bytes_count */
|
||||
|
||||
/**
|
||||
* Get hash value of the record's charset.
|
||||
*
|
||||
* @return hash value of the string
|
||||
*/
|
||||
lit_string_hash_t
|
||||
rcs_record_get_hash (rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p));
|
||||
|
||||
return (lit_string_hash_t) rcs_record_get_field (rec_p, RCS_CHARSET_HEADER_HASH_POS, RCS_CHARSET_HEADER_HASH_WIDTH);
|
||||
} /* rcs_record_get_hash */
|
||||
|
||||
/**
|
||||
* Get header size of the records.
|
||||
*
|
||||
* @return size of the header in bytes
|
||||
*/
|
||||
size_t
|
||||
rcs_header_get_size (rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
if (RCS_RECORD_IS_CHARSET (rec_p))
|
||||
{
|
||||
return RCS_CHARSET_HEADER_SIZE;
|
||||
}
|
||||
|
||||
return RCS_DYN_STORAGE_LENGTH_UNIT;
|
||||
} /* rcs_header_get_size */
|
||||
|
||||
/**
|
||||
* Get size of the records.
|
||||
*
|
||||
* @return size of the record in bytes
|
||||
*/
|
||||
size_t
|
||||
rcs_record_get_size (rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
switch (rcs_record_get_type (rec_p))
|
||||
{
|
||||
case RCS_RECORD_TYPE_CHARSET:
|
||||
{
|
||||
size_t size = rcs_record_get_field (rec_p, RCS_CHARSET_HEADER_LENGTH_POS, RCS_CHARSET_HEADER_LENGTH_WIDTH);
|
||||
return (size * RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
}
|
||||
case RCS_RECORD_TYPE_FREE:
|
||||
{
|
||||
size_t size = rcs_record_get_field (rec_p, RCS_FREE_HEADER_LENGTH_POS, RCS_FREE_HEADER_LENGTH_WIDTH);
|
||||
return (size * RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
}
|
||||
case RCS_RECORD_TYPE_NUMBER:
|
||||
{
|
||||
return (RCS_DYN_STORAGE_LENGTH_UNIT + sizeof (ecma_number_t));
|
||||
}
|
||||
case RCS_RECORD_TYPE_MAGIC_STR:
|
||||
case RCS_RECORD_TYPE_MAGIC_STR_EX:
|
||||
{
|
||||
return RCS_DYN_STORAGE_LENGTH_UNIT;
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} /* rcs_record_get_size */
|
||||
|
||||
/**
|
||||
* Get the length of the string, which is contained inside the record.
|
||||
*
|
||||
* @return length of the string (bytes count)
|
||||
*/
|
||||
lit_utf8_size_t
|
||||
rcs_record_get_length (rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p));
|
||||
|
||||
size_t record_size = rcs_record_get_size (rec_p);
|
||||
size_t align_count = rcs_record_get_alignment_bytes_count (rec_p);
|
||||
|
||||
return (lit_utf8_size_t) (record_size - RCS_CHARSET_HEADER_SIZE - align_count);
|
||||
} /* rcs_record_get_length */
|
||||
|
||||
/**
|
||||
* Get magic string id which is held by the record.
|
||||
*
|
||||
* @return magic string id
|
||||
*/
|
||||
lit_magic_string_id_t
|
||||
rcs_record_get_magic_str_id (rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_MAGIC_STR (rec_p));
|
||||
|
||||
return (lit_magic_string_id_t) rcs_record_get_field (rec_p,
|
||||
RCS_MAGIC_STR_HEADER_ID_POS,
|
||||
RCS_MAGIC_STR_HEADER_ID_WIDTH);
|
||||
} /* rcs_record_get_magic_str_id */
|
||||
|
||||
/**
|
||||
* Get external magic string id which is held by the record.
|
||||
*
|
||||
* @return external magic string id
|
||||
*/
|
||||
lit_magic_string_ex_id_t
|
||||
rcs_record_get_magic_str_ex_id (rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_MAGIC_STR_EX (rec_p));
|
||||
|
||||
return (lit_magic_string_ex_id_t) rcs_record_get_field (rec_p,
|
||||
RCS_MAGIC_STR_HEADER_ID_POS,
|
||||
RCS_MAGIC_STR_HEADER_ID_WIDTH);
|
||||
} /* rcs_record_get_magic_str_ex_id */
|
||||
|
||||
/**
|
||||
* Get the number which is held by the record.
|
||||
*
|
||||
* @return number
|
||||
*/
|
||||
ecma_number_t
|
||||
rcs_record_get_number (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_NUMBER (rec_p));
|
||||
|
||||
rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p);
|
||||
rcs_iterator_skip (&it_ctx, RCS_NUMBER_HEADER_SIZE);
|
||||
|
||||
ecma_number_t value;
|
||||
rcs_iterator_read (&it_ctx, &value, sizeof (ecma_number_t));
|
||||
|
||||
return value;
|
||||
} /* rcs_record_get_number */
|
||||
|
||||
/**
|
||||
* Get the characters which are stored to the record.
|
||||
*
|
||||
* @return number of code units written to the buffer
|
||||
*/
|
||||
lit_utf8_size_t
|
||||
rcs_record_get_charset (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_t *rec_p, /**< record */
|
||||
const lit_utf8_byte_t *buff_p, /**< output buffer */
|
||||
size_t buff_size) /**< size of the output buffer in bytes */
|
||||
{
|
||||
JERRY_ASSERT (RCS_RECORD_IS_CHARSET (rec_p));
|
||||
JERRY_ASSERT (buff_p && buff_size >= sizeof (lit_utf8_byte_t));
|
||||
|
||||
rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p);
|
||||
rcs_iterator_skip (&it_ctx, RCS_CHARSET_HEADER_SIZE);
|
||||
|
||||
lit_utf8_size_t str_len = rcs_record_get_length (rec_p);
|
||||
lit_utf8_size_t i;
|
||||
|
||||
for (i = 0; i < str_len && buff_size > 0; ++i)
|
||||
{
|
||||
rcs_iterator_read (&it_ctx, (void *)(buff_p + i), sizeof (lit_utf8_byte_t));
|
||||
rcs_iterator_skip (&it_ctx, sizeof (lit_utf8_byte_t));
|
||||
buff_size -= sizeof (lit_utf8_byte_t);
|
||||
}
|
||||
|
||||
return i;
|
||||
} /* rcs_record_get_charset */
|
||||
|
||||
/**
|
||||
* Get the first record of the recordset.
|
||||
*
|
||||
* @return pointer of the first record of the recordset
|
||||
*/
|
||||
rcs_record_t *
|
||||
rcs_record_get_first (rcs_record_set_t *rec_set_p) /**< recordset */
|
||||
{
|
||||
rcs_chunked_list_t::node_t *first_node_p = rec_set_p->get_first ();
|
||||
|
||||
if (first_node_p == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (rcs_record_t *) rcs_get_node_data_space (rec_set_p, first_node_p);
|
||||
} /* rcs_record_get_first */
|
||||
|
||||
/**
|
||||
* Get record, next to the specified.
|
||||
*
|
||||
* @return pointer to the next record
|
||||
*/
|
||||
rcs_record_t *
|
||||
rcs_record_get_next (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_t *rec_p) /**< record */
|
||||
{
|
||||
rcs_chunked_list_t::node_t *node_p = rec_set_p->get_node_from_pointer (rec_p);
|
||||
|
||||
const uint8_t *data_space_begin_p = rcs_get_node_data_space (rec_set_p, node_p);
|
||||
const size_t data_space_size = rcs_get_node_data_space_size ();
|
||||
|
||||
const uint8_t *record_start_p = (const uint8_t *) rec_p;
|
||||
const size_t record_size = rcs_record_get_size (rec_p);
|
||||
|
||||
const size_t record_offset_in_node = (size_t) (record_start_p - data_space_begin_p);
|
||||
const size_t node_size_left = data_space_size - record_offset_in_node;
|
||||
|
||||
if (node_size_left > record_size)
|
||||
{
|
||||
return (rcs_record_t *) (record_start_p + record_size);
|
||||
}
|
||||
|
||||
node_p = rec_set_p->get_next (node_p);
|
||||
JERRY_ASSERT (node_p != NULL || record_size == node_size_left);
|
||||
|
||||
size_t record_size_left = record_size - node_size_left;
|
||||
while (record_size_left >= data_space_size)
|
||||
{
|
||||
JERRY_ASSERT (node_p != NULL);
|
||||
|
||||
node_p = rec_set_p->get_next (node_p);
|
||||
record_size_left -= data_space_size;
|
||||
}
|
||||
|
||||
if (node_p == NULL)
|
||||
{
|
||||
JERRY_ASSERT (record_size_left == 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (rcs_record_t *) (rcs_get_node_data_space (rec_set_p, node_p) + record_size_left);
|
||||
} /* rcs_record_get_next */
|
||||
|
||||
/**
|
||||
* Compares two charset records for equality.
|
||||
*
|
||||
* @return true if strings inside records are equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
rcs_record_is_equal (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_t *l_rec_p, /**< left record */
|
||||
rcs_record_t *r_rec_p) /**< rigth record */
|
||||
{
|
||||
size_t l_rec_length = rcs_record_get_length (l_rec_p);
|
||||
size_t r_rec_length = rcs_record_get_length (r_rec_p);
|
||||
|
||||
if (l_rec_length != r_rec_length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rcs_iterator_t l_rec_it_ctx = rcs_iterator_create (rec_set_p, l_rec_p);
|
||||
rcs_iterator_t r_rec_it_ctx = rcs_iterator_create (rec_set_p, r_rec_p);
|
||||
|
||||
rcs_iterator_skip (&l_rec_it_ctx, RCS_CHARSET_HEADER_SIZE);
|
||||
rcs_iterator_skip (&r_rec_it_ctx, RCS_CHARSET_HEADER_SIZE);
|
||||
|
||||
lit_utf8_size_t i;
|
||||
for (i = 0; i < l_rec_length; ++i)
|
||||
{
|
||||
lit_utf8_byte_t l_chr;
|
||||
lit_utf8_byte_t r_chr;
|
||||
|
||||
rcs_iterator_read (&l_rec_it_ctx, &l_chr, sizeof (lit_utf8_byte_t));
|
||||
rcs_iterator_read (&r_rec_it_ctx, &r_chr, sizeof (lit_utf8_byte_t));
|
||||
|
||||
if (l_chr != r_chr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rcs_iterator_skip (&l_rec_it_ctx, sizeof (lit_utf8_byte_t));
|
||||
rcs_iterator_skip (&r_rec_it_ctx, sizeof (lit_utf8_byte_t));
|
||||
}
|
||||
|
||||
return true;
|
||||
} /* rcs_record_is_equal */
|
||||
|
||||
/**
|
||||
* Compare a record with a string (which could contain '\0' characters) for equality.
|
||||
*
|
||||
* @return true if compared instances are equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
rcs_record_is_equal_charset (rcs_record_set_t *rec_set_p, /**< recordset */
|
||||
rcs_record_t *rec_p, /**< record */
|
||||
const lit_utf8_byte_t *str_p, /**< string to compare with */
|
||||
lit_utf8_size_t str_size) /**< length of the string */
|
||||
{
|
||||
JERRY_ASSERT (str_p != NULL);
|
||||
|
||||
size_t rec_length = rcs_record_get_length (rec_p);
|
||||
|
||||
if (rec_length != str_size)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rcs_iterator_t it_ctx = rcs_iterator_create (rec_set_p, rec_p);
|
||||
rcs_iterator_skip (&it_ctx, RCS_CHARSET_HEADER_SIZE);
|
||||
|
||||
lit_utf8_size_t i;
|
||||
for (i = 0; i < rec_length; ++i)
|
||||
{
|
||||
lit_utf8_byte_t chr;
|
||||
rcs_iterator_read (&it_ctx, &chr, sizeof (lit_utf8_byte_t));
|
||||
|
||||
if (chr != str_p[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rcs_iterator_skip (&it_ctx, sizeof (lit_utf8_byte_t));
|
||||
}
|
||||
|
||||
return true;
|
||||
} /* rcs_record_is_equal_charset */
|
||||
@@ -0,0 +1,169 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
* Copyright 2015 University of Szeged
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef RCS_RECORDS_H
|
||||
#define RCS_RECORDS_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
|
||||
#define RCS_RECORD_TYPE_FIRST RCS_RECORD_TYPE_CHARSET
|
||||
#define RCS_RECORD_TYPE_LAST RCS_RECORD_TYPE_NUMBER
|
||||
#define RCS_RECORD_TYPE_MIN RCS_RECORD_TYPE_FREE
|
||||
#define RCS_RECORD_TYPE_MAX RCS_RECORD_TYPE_NUMBER
|
||||
|
||||
#define RCS_RECORD_TYPE_IS_FREE(type) ((type) == RCS_RECORD_TYPE_FREE)
|
||||
#define RCS_RECORD_TYPE_IS_NUMBER(type) ((type) == RCS_RECORD_TYPE_NUMBER)
|
||||
#define RCS_RECORD_TYPE_IS_CHARSET(type) ((type) == RCS_RECORD_TYPE_CHARSET)
|
||||
#define RCS_RECORD_TYPE_IS_MAGIC_STR(type) ((type) == RCS_RECORD_TYPE_MAGIC_STR)
|
||||
#define RCS_RECORD_TYPE_IS_MAGIC_STR_EX(type) ((type) == RCS_RECORD_TYPE_MAGIC_STR_EX)
|
||||
#define RCS_RECORD_TYPE_IS_VALID(type) ((type) <= RCS_RECORD_TYPE_MAX)
|
||||
|
||||
#define RCS_RECORD_IS_FREE(rec) (RCS_RECORD_TYPE_IS_FREE (rcs_record_get_type (rec)))
|
||||
#define RCS_RECORD_IS_NUMBER(rec) (RCS_RECORD_TYPE_IS_NUMBER (rcs_record_get_type (rec)))
|
||||
#define RCS_RECORD_IS_CHARSET(rec) (RCS_RECORD_TYPE_IS_CHARSET (rcs_record_get_type (rec)))
|
||||
#define RCS_RECORD_IS_MAGIC_STR(rec) (RCS_RECORD_TYPE_IS_MAGIC_STR (rcs_record_get_type (rec)))
|
||||
#define RCS_RECORD_IS_MAGIC_STR_EX(rec) (RCS_RECORD_TYPE_IS_MAGIC_STR_EX (rcs_record_get_type (rec)))
|
||||
|
||||
/**
|
||||
* Common header informations.
|
||||
*/
|
||||
#define RCS_HEADER_TYPE_POS 0u
|
||||
#define RCS_HEADER_TYPE_WIDTH 4u
|
||||
|
||||
#define RCS_HEADER_FIELD_BEGIN_POS (RCS_HEADER_TYPE_POS + RCS_HEADER_TYPE_WIDTH)
|
||||
|
||||
/**
|
||||
* Number record
|
||||
* Doesn't hold any characters, holds a number.
|
||||
* Numbers from source code are represented as number literals.
|
||||
*
|
||||
* Layout:
|
||||
* ------- header -----------------------
|
||||
* type (4 bits)
|
||||
* padding (12 bits)
|
||||
* pointer to prev (16 bits)
|
||||
* --------------------------------------
|
||||
* ecma_number_t
|
||||
*/
|
||||
#define RCS_NUMBER_HEADER_SIZE RCS_DYN_STORAGE_LENGTH_UNIT
|
||||
#define RCS_NUMBER_HEADER_PREV_POS (RCS_HEADER_FIELD_BEGIN_POS + 12u)
|
||||
|
||||
/**
|
||||
* Charset record
|
||||
*
|
||||
* layout:
|
||||
* ------- header -----------------------
|
||||
* type (4 bits)
|
||||
* alignment (2 bits)
|
||||
* unused (2 bits)
|
||||
* hash (8 bits)
|
||||
* length (16 bits)
|
||||
* pointer to prev (16 bits)
|
||||
* ------- characters -------------------
|
||||
* ...
|
||||
* chars
|
||||
* ....
|
||||
* ------- alignment bytes --------------
|
||||
* unused bytes (their count is specified
|
||||
* by 'alignment' field in header)
|
||||
* --------------------------------------
|
||||
*/
|
||||
#define RCS_CHARSET_HEADER_SIZE (RCS_DYN_STORAGE_LENGTH_UNIT + RCS_DYN_STORAGE_LENGTH_UNIT / 2)
|
||||
|
||||
#define RCS_CHARSET_HEADER_ALIGN_POS RCS_HEADER_FIELD_BEGIN_POS
|
||||
#define RCS_CHARSET_HEADER_ALIGN_WIDTH RCS_DYN_STORAGE_LENGTH_UNIT_LOG
|
||||
|
||||
#define RCS_CHARSET_HEADER_UNUSED_POS (RCS_CHARSET_HEADER_ALIGN_POS + RCS_CHARSET_HEADER_ALIGN_WIDTH)
|
||||
#define RCS_CHARSET_HEADER_UNUSED_WIDTH 2u
|
||||
|
||||
#define RCS_CHARSET_HEADER_HASH_POS (RCS_CHARSET_HEADER_UNUSED_POS + RCS_CHARSET_HEADER_UNUSED_WIDTH)
|
||||
#define RCS_CHARSET_HEADER_HASH_WIDTH 8u
|
||||
|
||||
#define RCS_CHARSET_HEADER_LENGTH_POS (RCS_CHARSET_HEADER_HASH_POS + RCS_CHARSET_HEADER_HASH_WIDTH)
|
||||
#define RCS_CHARSET_HEADER_LENGTH_WIDTH 16u
|
||||
|
||||
#define RCS_CHARSET_HEADER_PREV_POS (RCS_CHARSET_HEADER_LENGTH_POS + RCS_CHARSET_HEADER_LENGTH_WIDTH)
|
||||
|
||||
/**
|
||||
* Magic string record
|
||||
* Doesn't hold any characters. Corresponding string is identified by its id.
|
||||
*
|
||||
* Layout:
|
||||
* ------- header -----------------------
|
||||
* type (4 bits)
|
||||
* magic string id (12 bits)
|
||||
* pointer to prev (16 bits)
|
||||
* --------------------------------------
|
||||
*/
|
||||
#define RCS_MAGIC_STR_HEADER_SIZE RCS_DYN_STORAGE_LENGTH_UNIT
|
||||
|
||||
#define RCS_MAGIC_STR_HEADER_ID_POS RCS_HEADER_FIELD_BEGIN_POS
|
||||
#define RCS_MAGIC_STR_HEADER_ID_WIDTH 12u
|
||||
|
||||
#define RCS_MAGIC_STR_HEADER_PREV_POS (RCS_MAGIC_STR_HEADER_ID_POS + RCS_MAGIC_STR_HEADER_ID_WIDTH)
|
||||
|
||||
/**
|
||||
* Free record
|
||||
* Doesn't hold any data.
|
||||
*
|
||||
* Layout:
|
||||
* ------- header -----------------------
|
||||
* type (4 bits)
|
||||
* length (12 bits)
|
||||
* pointer to prev (16 bits)
|
||||
* --------------------------------------
|
||||
*/
|
||||
#define RCS_FREE_HEADER_SIZE RCS_DYN_STORAGE_LENGTH_UNIT
|
||||
|
||||
#define RCS_FREE_HEADER_LENGTH_POS RCS_HEADER_FIELD_BEGIN_POS
|
||||
#define RCS_FREE_HEADER_LENGTH_WIDTH (14u - RCS_DYN_STORAGE_LENGTH_UNIT_LOG)
|
||||
|
||||
#define RCS_FREE_HEADER_PREV_POS (RCS_FREE_HEADER_LENGTH_POS + RCS_FREE_HEADER_LENGTH_WIDTH)
|
||||
|
||||
/*
|
||||
* Setters
|
||||
*/
|
||||
extern void rcs_record_set_type (rcs_record_t *, rcs_record_type_t);
|
||||
extern void rcs_record_set_prev (rcs_record_set_t *, rcs_record_t *, rcs_record_t *);
|
||||
extern void rcs_record_set_size (rcs_record_t *, size_t);
|
||||
extern void rcs_record_set_alignment_bytes_count (rcs_record_t *, size_t);
|
||||
extern void rcs_record_set_hash (rcs_record_t *, lit_string_hash_t);
|
||||
extern void rcs_record_set_charset (rcs_record_set_t *, rcs_record_t *, const lit_utf8_byte_t *, lit_utf8_size_t);
|
||||
extern void rcs_record_set_magic_str_id (rcs_record_t *, lit_magic_string_id_t);
|
||||
extern void rcs_record_set_magic_str_ex_id (rcs_record_t *, lit_magic_string_ex_id_t);
|
||||
|
||||
/*
|
||||
* Getters
|
||||
*/
|
||||
extern rcs_record_type_t rcs_record_get_type (rcs_record_t *);
|
||||
extern rcs_record_t *rcs_record_get_prev (rcs_record_set_t *, rcs_record_t *);
|
||||
extern size_t rcs_record_get_size (rcs_record_t *);
|
||||
extern size_t rcs_header_get_size (rcs_record_t *);
|
||||
extern size_t rcs_record_get_alignment_bytes_count (rcs_record_t *);
|
||||
extern lit_string_hash_t rcs_record_get_hash (rcs_record_t *);
|
||||
extern lit_utf8_size_t rcs_record_get_length (rcs_record_t *);
|
||||
extern lit_utf8_size_t rcs_record_get_charset (rcs_record_set_t *, rcs_record_t *, const lit_utf8_byte_t *, size_t);
|
||||
extern lit_magic_string_id_t rcs_record_get_magic_str_id (rcs_record_t *);
|
||||
extern lit_magic_string_ex_id_t rcs_record_get_magic_str_ex_id (rcs_record_t *);
|
||||
extern ecma_number_t rcs_record_get_number (rcs_record_set_t *, rcs_record_t *);
|
||||
|
||||
extern rcs_record_t *rcs_record_get_first (rcs_record_set_t *);
|
||||
extern rcs_record_t *rcs_record_get_next (rcs_record_set_t *, rcs_record_t *);
|
||||
|
||||
extern bool rcs_record_is_equal (rcs_record_set_t *, rcs_record_t *, rcs_record_t *);
|
||||
extern bool rcs_record_is_equal_charset (rcs_record_set_t *, rcs_record_t *, const lit_utf8_byte_t *, lit_utf8_size_t);
|
||||
|
||||
#endif /* !RCS_RECORDS_H */
|
||||
@@ -1,864 +0,0 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "rcs-chunked-list.h"
|
||||
#include "rcs-recordset.h"
|
||||
|
||||
/** \addtogroup recordset Recordset
|
||||
* @{
|
||||
*
|
||||
* Non-contiguous container abstraction with iterator.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the record's type identifier
|
||||
*
|
||||
* @return record type identifier
|
||||
*/
|
||||
rcs_record_t::type_t
|
||||
rcs_recordset_t::record_t::get_type (void)
|
||||
const
|
||||
{
|
||||
JERRY_STATIC_ASSERT (sizeof (type_t) * JERRY_BITSINBYTE >= _type_field_width);
|
||||
|
||||
return (type_t) get_field (_type_field_pos, _type_field_width);
|
||||
} /* rcs_recordset_t::record_t::get_type */
|
||||
|
||||
/**
|
||||
* Set the record's type identifier
|
||||
*/
|
||||
void
|
||||
rcs_recordset_t::record_t::set_type (rcs_record_t::type_t type) /**< record type identifier */
|
||||
{
|
||||
set_field (_type_field_pos, _type_field_width, type);
|
||||
} /* rcs_recordset_t::record_t::set_type */
|
||||
|
||||
/**
|
||||
* Compress pointer to extended compressed pointer
|
||||
*
|
||||
* @return dynamic storage-specific extended compressed pointer
|
||||
*/
|
||||
rcs_cpointer_t
|
||||
rcs_recordset_t::record_t::cpointer_t::compress (rcs_record_t *pointer) /**< pointer to compress */
|
||||
{
|
||||
rcs_cpointer_t cpointer;
|
||||
|
||||
cpointer.packed_value = 0;
|
||||
|
||||
uintptr_t base_pointer = JERRY_ALIGNDOWN ((uintptr_t) pointer, MEM_ALIGNMENT);
|
||||
|
||||
if ((void *) base_pointer == NULL)
|
||||
{
|
||||
cpointer.value.base_cp = MEM_CP_NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
cpointer.value.base_cp = mem_compress_pointer ((void *) base_pointer) & MEM_CP_MASK;
|
||||
}
|
||||
|
||||
#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG
|
||||
/*
|
||||
* If alignment of a unit in recordset storage is less than required by MEM_ALIGNMENT_LOG,
|
||||
* then mem_cpointer_t can't store pointer to the unit, and so, rcs_cpointer_t stores
|
||||
* mem_cpointer_t to block, aligned to MEM_ALIGNMENT, and also extension with difference
|
||||
* between positions of the MEM_ALIGNMENT-aligned block and the unit.
|
||||
*/
|
||||
uintptr_t diff = (uintptr_t) pointer - base_pointer;
|
||||
|
||||
JERRY_ASSERT (diff < MEM_ALIGNMENT);
|
||||
JERRY_ASSERT (jrt_extract_bit_field (diff, 0, RCS_DYN_STORAGE_LENGTH_UNIT_LOG) == 0);
|
||||
|
||||
uintptr_t ext_part = (uintptr_t) jrt_extract_bit_field (diff,
|
||||
RCS_DYN_STORAGE_LENGTH_UNIT_LOG,
|
||||
MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG);
|
||||
|
||||
cpointer.value.ext = ext_part & ((1ull << (MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG)) - 1);
|
||||
#endif /* MEM_ALIGNMENT > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */
|
||||
|
||||
JERRY_ASSERT (decompress (cpointer) == pointer);
|
||||
|
||||
return cpointer;
|
||||
} /* rcs_recordset_t::record_t::cpointer_t::compress */
|
||||
|
||||
/**
|
||||
* Decompress extended compressed pointer
|
||||
*
|
||||
* @return decompressed pointer
|
||||
*/
|
||||
rcs_record_t*
|
||||
rcs_recordset_t::record_t::cpointer_t::decompress (rcs_cpointer_t compressed_pointer) /**< recordset-specific
|
||||
* compressed pointer */
|
||||
{
|
||||
uint8_t* base_pointer;
|
||||
if (compressed_pointer.value.base_cp == MEM_CP_NULL)
|
||||
{
|
||||
base_pointer = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
base_pointer = (uint8_t*) mem_decompress_pointer (compressed_pointer.value.base_cp);
|
||||
}
|
||||
|
||||
uintptr_t diff = 0;
|
||||
|
||||
#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG
|
||||
/*
|
||||
* See also:
|
||||
* rcs_recordset_t::record_t::cpointer_t::compress
|
||||
*/
|
||||
|
||||
diff = (uintptr_t) compressed_pointer.value.ext << RCS_DYN_STORAGE_LENGTH_UNIT_LOG;
|
||||
#endif /* MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */
|
||||
|
||||
rcs_record_t *rec_p = (rcs_record_t *) (base_pointer + diff);
|
||||
|
||||
return rec_p;
|
||||
} /* rcs_recordset_t::record_t::cpointer_t::decompress */
|
||||
|
||||
/**
|
||||
* Create NULL compressed pointer
|
||||
*
|
||||
* @return NULL compressed pointer
|
||||
*/
|
||||
rcs_cpointer_t
|
||||
rcs_recordset_t::record_t::cpointer_t::null_cp ()
|
||||
{
|
||||
rcs_cpointer_t cp;
|
||||
cp.packed_value = MEM_CP_NULL;
|
||||
return cp;
|
||||
} /* rcs_recordset_t::record_t::cpointer_t::null_cp */
|
||||
|
||||
/**
|
||||
* Assert that 'this' value points to correct record
|
||||
*/
|
||||
void
|
||||
rcs_recordset_t::record_t::check_this (void)
|
||||
const
|
||||
{
|
||||
JERRY_ASSERT (this != NULL);
|
||||
|
||||
uintptr_t ptr = (uintptr_t) this;
|
||||
|
||||
JERRY_ASSERT (JERRY_ALIGNUP (ptr, RCS_DYN_STORAGE_LENGTH_UNIT) == ptr);
|
||||
} /* rcs_recordset_t::record_t::check_this */
|
||||
|
||||
/**
|
||||
* Get value of the record's field with specified offset and width
|
||||
*
|
||||
* @return field's 32-bit unsigned integer value
|
||||
*/
|
||||
uint32_t
|
||||
rcs_recordset_t::record_t::get_field (uint32_t field_pos, /**< offset, in bits */
|
||||
uint32_t field_width) /**< width, in bits */
|
||||
const
|
||||
{
|
||||
check_this ();
|
||||
|
||||
JERRY_ASSERT (sizeof (uint32_t) <= RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
JERRY_ASSERT (field_pos + field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE);
|
||||
|
||||
uint32_t value = *reinterpret_cast<const uint32_t*> (this);
|
||||
return (uint32_t) jrt_extract_bit_field (value, field_pos, field_width);
|
||||
} /* rcs_recordset_t::record_t::get_field */
|
||||
|
||||
/**
|
||||
* Set value of the record's field with specified offset and width
|
||||
*/
|
||||
void
|
||||
rcs_recordset_t::record_t::set_field (uint32_t field_pos, /**< offset, in bits */
|
||||
uint32_t field_width, /**< width, in bits */
|
||||
size_t value) /**< 32-bit unsigned integer value */
|
||||
{
|
||||
check_this ();
|
||||
|
||||
JERRY_ASSERT (sizeof (uint32_t) <= RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
JERRY_ASSERT (field_pos + field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE);
|
||||
|
||||
uint32_t prev_value = *reinterpret_cast<uint32_t*> (this);
|
||||
*reinterpret_cast<uint32_t*> (this) = (uint32_t) jrt_set_bit_field_value (prev_value,
|
||||
value,
|
||||
field_pos,
|
||||
field_width);
|
||||
} /* rcs_recordset_t::record_t::set_field */
|
||||
|
||||
/**
|
||||
* Get value of the record's pointer field with specified offset and width
|
||||
*
|
||||
* @return pointer to record
|
||||
*/
|
||||
rcs_record_t*
|
||||
rcs_recordset_t::record_t::get_pointer (uint32_t field_pos, /**< offset, in bits */
|
||||
uint32_t field_width) /**< width, in bits */
|
||||
const
|
||||
{
|
||||
cpointer_t cpointer;
|
||||
|
||||
uint16_t value = (uint16_t) get_field (field_pos, field_width);
|
||||
|
||||
JERRY_ASSERT (sizeof (cpointer) == sizeof (cpointer.value));
|
||||
JERRY_ASSERT (sizeof (value) == sizeof (cpointer.value));
|
||||
|
||||
cpointer.packed_value = value;
|
||||
|
||||
return cpointer_t::decompress (cpointer);
|
||||
} /* rcs_recordset_t::record_t::get_pointer */
|
||||
|
||||
/**
|
||||
* Set value of the record's pointer field with specified offset and width
|
||||
*/
|
||||
void
|
||||
rcs_recordset_t::record_t::set_pointer (uint32_t field_pos, /**< offset, in bits */
|
||||
uint32_t field_width, /**< width, in bits */
|
||||
rcs_record_t* pointer_p) /**< pointer to a record */
|
||||
{
|
||||
cpointer_t cpointer = cpointer_t::compress (pointer_p);
|
||||
|
||||
set_field (field_pos, field_width, cpointer.packed_value);
|
||||
} /* rcs_recordset_t::record_t::set_pointer */
|
||||
|
||||
/**
|
||||
* Initialize record in specified place, and, if there is free space
|
||||
* before next record, initialize free record for the space
|
||||
*/
|
||||
void
|
||||
rcs_recordset_t::alloc_record_in_place (rcs_record_t* place_p, /**< where to initialize record */
|
||||
size_t free_size, /**< size of free part between allocated record
|
||||
* and next allocated record */
|
||||
rcs_record_t* next_record_p) /**< next allocated record */
|
||||
{
|
||||
const size_t node_data_space_size = get_node_data_space_size ();
|
||||
|
||||
if (next_record_p != NULL)
|
||||
{
|
||||
if (free_size == 0)
|
||||
{
|
||||
set_prev (next_record_p, place_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
rcs_chunked_list_t::node_t* node_p = _chunk_list.get_node_from_pointer (next_record_p);
|
||||
uint8_t* node_data_space_p = get_node_data_space (node_p);
|
||||
|
||||
JERRY_ASSERT ((uint8_t*) next_record_p < node_data_space_p + node_data_space_size);
|
||||
|
||||
rcs_record_t* free_rec_p;
|
||||
|
||||
if ((uint8_t*) next_record_p >= node_data_space_p + free_size)
|
||||
{
|
||||
free_rec_p = (rcs_record_t*) ((uint8_t*) next_record_p - free_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size_passed_back = (size_t) ((uint8_t*) next_record_p - node_data_space_p);
|
||||
JERRY_ASSERT (size_passed_back < free_size && size_passed_back + node_data_space_size > free_size);
|
||||
|
||||
node_p = _chunk_list.get_prev (node_p);
|
||||
node_data_space_p = get_node_data_space (node_p);
|
||||
|
||||
free_rec_p = (rcs_record_t*) (node_data_space_p + node_data_space_size - \
|
||||
(free_size - size_passed_back));
|
||||
}
|
||||
|
||||
init_free_record (free_rec_p, free_size, place_p);
|
||||
}
|
||||
}
|
||||
else if (free_size != 0)
|
||||
{
|
||||
rcs_chunked_list_t::node_t* node_p = _chunk_list.get_node_from_pointer (place_p);
|
||||
JERRY_ASSERT (node_p != NULL);
|
||||
|
||||
rcs_chunked_list_t::node_t* next_node_p = _chunk_list.get_next (node_p);
|
||||
|
||||
while (next_node_p != NULL)
|
||||
{
|
||||
node_p = next_node_p;
|
||||
|
||||
next_node_p = _chunk_list.get_next (node_p);
|
||||
}
|
||||
|
||||
uint8_t* node_data_space_p = get_node_data_space (node_p);
|
||||
const size_t node_data_space_size = get_node_data_space_size ();
|
||||
|
||||
rcs_record_t* free_rec_p = (rcs_record_t*) (node_data_space_p + node_data_space_size \
|
||||
- free_size);
|
||||
init_free_record (free_rec_p, free_size, place_p);
|
||||
}
|
||||
} /* rcs_recordset_t::alloc_record_in_place */
|
||||
|
||||
/**
|
||||
* Initialize specified record as free record
|
||||
*/
|
||||
void
|
||||
rcs_recordset_t::init_free_record (rcs_record_t *rec_p, /**< record to init as free record */
|
||||
size_t size, /**< size, including header */
|
||||
rcs_record_t *prev_rec_p) /**< previous record (or NULL) */
|
||||
{
|
||||
rcs_free_record_t *free_rec_p = static_cast<rcs_free_record_t*> (rec_p);
|
||||
|
||||
free_rec_p->set_type (_free_record_type_id);
|
||||
free_rec_p->set_size (size);
|
||||
free_rec_p->set_prev (prev_rec_p);
|
||||
} /* rcs_recordset_t::init_free_record */
|
||||
|
||||
/**
|
||||
* Check if the record is free record
|
||||
*/
|
||||
bool
|
||||
rcs_recordset_t::is_record_free (rcs_record_t *record_p) /**< a record */
|
||||
{
|
||||
JERRY_ASSERT (record_p != NULL);
|
||||
|
||||
return (record_p->get_type () == _free_record_type_id);
|
||||
} /* rcs_recordset_t::is_record_free */
|
||||
|
||||
/**
|
||||
* Get the node's data space
|
||||
*
|
||||
* @return pointer to beginning of the node's data space
|
||||
*/
|
||||
uint8_t *
|
||||
rcs_recordset_t::get_node_data_space (rcs_chunked_list_t::node_t *node_p) /**< the node */
|
||||
const
|
||||
{
|
||||
uintptr_t unaligned_data_space_beg = (uintptr_t) _chunk_list.get_node_data_space (node_p);
|
||||
uintptr_t aligned_data_space_beg = JERRY_ALIGNUP (unaligned_data_space_beg, RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
|
||||
JERRY_ASSERT (unaligned_data_space_beg + rcs_chunked_list_t::get_node_data_space_size ()
|
||||
== aligned_data_space_beg + rcs_recordset_t::get_node_data_space_size ());
|
||||
|
||||
return (uint8_t *) aligned_data_space_beg;
|
||||
} /* rcs_recordset_t::get_node_data_space */
|
||||
|
||||
/**
|
||||
* Get size of a node's data space
|
||||
*
|
||||
* @return size
|
||||
*/
|
||||
size_t
|
||||
rcs_recordset_t::get_node_data_space_size (void)
|
||||
{
|
||||
return JERRY_ALIGNDOWN (rcs_chunked_list_t::get_node_data_space_size (), RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
} /* rcs_recordset_t::get_node_data_space_size */
|
||||
|
||||
/**
|
||||
* Allocate record of specified size
|
||||
*
|
||||
* @return record identifier
|
||||
*/
|
||||
rcs_record_t*
|
||||
rcs_recordset_t::alloc_space_for_record (size_t bytes, /**< size */
|
||||
rcs_record_t** out_prev_rec_p) /**< out: pointer to record, previous
|
||||
* to the allocated, or NULL if the allocated
|
||||
* record is the first */
|
||||
{
|
||||
assert_state_is_correct ();
|
||||
|
||||
JERRY_ASSERT (JERRY_ALIGNUP (bytes, RCS_DYN_STORAGE_LENGTH_UNIT) == bytes);
|
||||
JERRY_ASSERT (out_prev_rec_p != NULL);
|
||||
|
||||
const size_t node_data_space_size = get_node_data_space_size ();
|
||||
|
||||
*out_prev_rec_p = NULL;
|
||||
|
||||
for (rcs_record_t *rec_p = get_first ();
|
||||
rec_p != NULL;
|
||||
*out_prev_rec_p = rec_p, rec_p = get_next (rec_p))
|
||||
{
|
||||
if (is_record_free (rec_p))
|
||||
{
|
||||
size_t record_size = get_record_size (rec_p);
|
||||
|
||||
rcs_record_t* next_rec_p = get_next (rec_p);
|
||||
|
||||
if (record_size >= bytes)
|
||||
{
|
||||
/* record size is sufficient */
|
||||
alloc_record_in_place (rec_p, record_size - bytes, next_rec_p);
|
||||
|
||||
return rec_p;
|
||||
}
|
||||
else
|
||||
{
|
||||
rcs_chunked_list_t::node_t* node_p = _chunk_list.get_node_from_pointer (rec_p);
|
||||
uint8_t* node_data_space_p = get_node_data_space (node_p);
|
||||
uint8_t* node_data_space_end_p = node_data_space_p + node_data_space_size;
|
||||
|
||||
uint8_t* rec_space_p = (uint8_t*) rec_p;
|
||||
|
||||
if (rec_space_p + record_size >= node_data_space_end_p)
|
||||
{
|
||||
/* record lies up to end of node's data space size,
|
||||
* and, so, can be extended up to necessary size */
|
||||
|
||||
while (record_size < bytes)
|
||||
{
|
||||
node_p = _chunk_list.insert_new (node_p);
|
||||
|
||||
record_size += node_data_space_size;
|
||||
}
|
||||
|
||||
alloc_record_in_place (rec_p, record_size - bytes, next_rec_p);
|
||||
|
||||
return rec_p;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_rec_p == NULL)
|
||||
{
|
||||
/* in the case, there are no more records in the storage,
|
||||
* so, we should append new record */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (!is_record_free (rec_p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free record of sufficient size was not found */
|
||||
|
||||
rcs_chunked_list_t::node_t *node_p = _chunk_list.append_new ();
|
||||
rcs_record_t* new_rec_p = (rcs_record_t*) get_node_data_space (node_p);
|
||||
|
||||
size_t allocated_size = node_data_space_size;
|
||||
|
||||
while (allocated_size < bytes)
|
||||
{
|
||||
allocated_size += node_data_space_size;
|
||||
_chunk_list.append_new ();
|
||||
}
|
||||
|
||||
alloc_record_in_place (new_rec_p, allocated_size - bytes, NULL);
|
||||
|
||||
return new_rec_p;
|
||||
} /* rcs_recordset_t::alloc_space_for_record */
|
||||
|
||||
/**
|
||||
* Free specified record
|
||||
*/
|
||||
void
|
||||
rcs_recordset_t::free_record (rcs_record_t* record_p) /**< record to free */
|
||||
{
|
||||
JERRY_ASSERT (record_p != NULL);
|
||||
|
||||
assert_state_is_correct ();
|
||||
|
||||
rcs_record_t *prev_rec_p = get_prev (record_p);
|
||||
|
||||
// make record free
|
||||
init_free_record (record_p, get_record_size (record_p), prev_rec_p);
|
||||
|
||||
// merge adjacent free records, if there are any,
|
||||
// and free nodes of chunked list that became unused
|
||||
rcs_record_t *rec_from_p = record_p, *rec_to_p = get_next (record_p);
|
||||
|
||||
if (prev_rec_p != NULL
|
||||
&& is_record_free (prev_rec_p))
|
||||
{
|
||||
rec_from_p = prev_rec_p;
|
||||
|
||||
prev_rec_p = get_prev (rec_from_p);
|
||||
}
|
||||
|
||||
if (rec_to_p != NULL
|
||||
&& is_record_free (rec_to_p))
|
||||
{
|
||||
rec_to_p = get_next (rec_to_p);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (rec_from_p != NULL && is_record_free (rec_from_p));
|
||||
JERRY_ASSERT (rec_to_p == NULL || !is_record_free (rec_to_p));
|
||||
|
||||
rcs_chunked_list_t::node_t *node_from_p = _chunk_list.get_node_from_pointer (rec_from_p);
|
||||
rcs_chunked_list_t::node_t *node_to_p;
|
||||
|
||||
if (rec_to_p == NULL)
|
||||
{
|
||||
node_to_p = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
node_to_p = _chunk_list.get_node_from_pointer (rec_to_p);
|
||||
}
|
||||
|
||||
const size_t node_data_space_size = get_node_data_space_size ();
|
||||
|
||||
uint8_t* rec_from_beg_p = (uint8_t*) rec_from_p;
|
||||
uint8_t* rec_to_beg_p = (uint8_t*) rec_to_p;
|
||||
size_t free_size;
|
||||
|
||||
if (node_from_p == node_to_p)
|
||||
{
|
||||
JERRY_ASSERT (rec_from_beg_p + get_record_size (rec_from_p) <= rec_to_beg_p);
|
||||
|
||||
free_size = (size_t) (rec_to_beg_p - rec_from_beg_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (rcs_chunked_list_t::node_t *iter_node_p = _chunk_list.get_next (node_from_p), *iter_next_node_p;
|
||||
iter_node_p != node_to_p;
|
||||
iter_node_p = iter_next_node_p)
|
||||
{
|
||||
iter_next_node_p = _chunk_list.get_next (iter_node_p);
|
||||
|
||||
_chunk_list.remove (iter_node_p);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (_chunk_list.get_next (node_from_p) == node_to_p);
|
||||
|
||||
size_t node_from_space = (size_t) (get_node_data_space (node_from_p) +
|
||||
node_data_space_size - rec_from_beg_p);
|
||||
size_t node_to_space = (size_t) (node_to_p != NULL
|
||||
? rec_to_beg_p - get_node_data_space (node_to_p)
|
||||
: 0);
|
||||
|
||||
free_size = node_from_space + node_to_space;
|
||||
}
|
||||
|
||||
init_free_record (rec_from_p, free_size, prev_rec_p);
|
||||
|
||||
if (rec_to_p != NULL)
|
||||
{
|
||||
set_prev (rec_to_p, rec_from_p);
|
||||
}
|
||||
else if (prev_rec_p == NULL)
|
||||
{
|
||||
JERRY_ASSERT (node_to_p == NULL);
|
||||
|
||||
_chunk_list.remove (node_from_p);
|
||||
|
||||
JERRY_ASSERT (_chunk_list.get_first () == NULL);
|
||||
}
|
||||
|
||||
assert_state_is_correct ();
|
||||
} /* rcs_recordset_t::free_record */
|
||||
|
||||
/**
|
||||
* Get first record
|
||||
*
|
||||
* @return pointer of the first record of the recordset
|
||||
*/
|
||||
rcs_record_t*
|
||||
rcs_recordset_t::get_first (void)
|
||||
{
|
||||
rcs_chunked_list_t::node_t *first_node_p = _chunk_list.get_first ();
|
||||
|
||||
if (first_node_p == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (rcs_record_t*) get_node_data_space (first_node_p);
|
||||
}
|
||||
} /* rcs_recordset_t::get_first */
|
||||
|
||||
/**
|
||||
* Get record, previous to the specified
|
||||
*
|
||||
* @return pointer to the previous record
|
||||
*/
|
||||
rcs_record_t*
|
||||
rcs_recordset_t::get_prev (rcs_record_t* rec_p) /**< record */
|
||||
{
|
||||
JERRY_ASSERT (rec_p->get_type () == _free_record_type_id);
|
||||
|
||||
rcs_free_record_t *free_rec_p = static_cast<rcs_free_record_t*> (rec_p);
|
||||
|
||||
return free_rec_p->get_prev ();
|
||||
} /* rcs_recordset_t::get_prev */
|
||||
|
||||
/**
|
||||
* Get record, next to the specified
|
||||
*
|
||||
* @return pointer to the next record
|
||||
*/
|
||||
rcs_record_t*
|
||||
rcs_recordset_t::get_next (rcs_record_t* rec_p) /**< record */
|
||||
{
|
||||
rcs_chunked_list_t::node_t* node_p = _chunk_list.get_node_from_pointer (rec_p);
|
||||
|
||||
const uint8_t* data_space_begin_p = get_node_data_space (node_p);
|
||||
const size_t data_space_size = get_node_data_space_size ();
|
||||
|
||||
const uint8_t* record_start_p = (const uint8_t*) rec_p;
|
||||
size_t record_size = get_record_size (rec_p);
|
||||
|
||||
size_t record_offset_in_node = (size_t) (record_start_p - data_space_begin_p);
|
||||
size_t node_size_left = data_space_size - record_offset_in_node;
|
||||
|
||||
if (node_size_left > record_size)
|
||||
{
|
||||
return (rcs_record_t*) (record_start_p + record_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
node_p = _chunk_list.get_next (node_p);
|
||||
JERRY_ASSERT (node_p != NULL || record_size == node_size_left);
|
||||
|
||||
size_t record_size_left = record_size - node_size_left;
|
||||
|
||||
while (record_size_left >= data_space_size)
|
||||
{
|
||||
JERRY_ASSERT (node_p != NULL);
|
||||
node_p = _chunk_list.get_next (node_p);
|
||||
|
||||
record_size_left -= data_space_size;
|
||||
}
|
||||
|
||||
if (node_p == NULL)
|
||||
{
|
||||
JERRY_ASSERT (record_size_left == 0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (rcs_record_t*) (get_node_data_space (node_p) + record_size_left);
|
||||
}
|
||||
}
|
||||
} /* rcs_recordset_t::get_next */
|
||||
|
||||
/**
|
||||
* Set previous record
|
||||
*/
|
||||
void
|
||||
rcs_recordset_t::set_prev (rcs_record_t* rec_p, /**< record to set previous for */
|
||||
rcs_record_t *prev_rec_p) /**< previous record */
|
||||
{
|
||||
JERRY_ASSERT (rec_p->get_type () == _free_record_type_id);
|
||||
|
||||
rcs_free_record_t *free_rec_p = static_cast<rcs_free_record_t*> (rec_p);
|
||||
|
||||
free_rec_p->set_prev (prev_rec_p);
|
||||
} /* rcs_recordset_t::set_prev */
|
||||
|
||||
/**
|
||||
* Get size of the record
|
||||
*/
|
||||
size_t
|
||||
rcs_recordset_t::get_record_size (rcs_record_t* rec_p) /**< record */
|
||||
{
|
||||
JERRY_ASSERT (rec_p->get_type () == _free_record_type_id);
|
||||
|
||||
rcs_free_record_t *free_rec_p = static_cast<rcs_free_record_t*> (rec_p);
|
||||
|
||||
return free_rec_p->get_size ();
|
||||
} /* rcs_recordset_t::get_record_size */
|
||||
|
||||
/**
|
||||
* Assert that recordset state is correct
|
||||
*/
|
||||
void
|
||||
rcs_recordset_t::assert_state_is_correct (void)
|
||||
{
|
||||
#ifndef JERRY_DISABLE_HEAVY_DEBUG
|
||||
size_t node_size_sum = 0;
|
||||
size_t record_size_sum = 0;
|
||||
|
||||
rcs_record_t* last_record_p = NULL;
|
||||
|
||||
for (rcs_record_t* rec_p = get_first (), *next_rec_p;
|
||||
rec_p != NULL;
|
||||
last_record_p = rec_p, rec_p = next_rec_p)
|
||||
{
|
||||
JERRY_ASSERT (get_record_size (rec_p) > 0);
|
||||
record_size_sum += get_record_size (rec_p);
|
||||
|
||||
rcs_chunked_list_t::node_t *node_p = _chunk_list.get_node_from_pointer (rec_p);
|
||||
|
||||
next_rec_p = get_next (rec_p);
|
||||
|
||||
rcs_chunked_list_t::node_t *next_node_p;
|
||||
if (next_rec_p == NULL)
|
||||
{
|
||||
next_node_p = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
next_node_p = _chunk_list.get_node_from_pointer (next_rec_p);
|
||||
}
|
||||
|
||||
while (node_p != next_node_p)
|
||||
{
|
||||
node_p = _chunk_list.get_next (node_p);
|
||||
node_size_sum += get_node_data_space_size ();
|
||||
}
|
||||
}
|
||||
|
||||
JERRY_ASSERT (node_size_sum == record_size_sum);
|
||||
|
||||
record_size_sum = 0;
|
||||
for (rcs_record_t* rec_p = last_record_p;
|
||||
rec_p != NULL;
|
||||
rec_p = get_prev (rec_p))
|
||||
{
|
||||
record_size_sum += get_record_size (rec_p);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (node_size_sum == record_size_sum);
|
||||
#endif /* !JERRY_DISABLE_HEAVY_DEBUG */
|
||||
} /* rcs_recordset_t::assert_state_is_correct */
|
||||
|
||||
/**
|
||||
* Perform general access to the record
|
||||
*
|
||||
* Warning: This function is implemented in assumption that `size` is not more than `2 * node_data_space_size`.
|
||||
*/
|
||||
void
|
||||
rcs_record_iterator_t::access (access_t access_type, /**< type of access: read, write or skip */
|
||||
void *data, /**< in/out data to read or write */
|
||||
size_t size) /**< size of the data in bytes */
|
||||
{
|
||||
const size_t node_data_space_size = _recordset_p->get_node_data_space_size ();
|
||||
JERRY_ASSERT (2 * node_data_space_size >= size);
|
||||
const size_t record_size = _recordset_p->get_record_size (_record_start_p);
|
||||
|
||||
JERRY_ASSERT (!finished ());
|
||||
|
||||
rcs_chunked_list_t::node_t *current_node_p = _recordset_p->_chunk_list.get_node_from_pointer (_current_pos_p);
|
||||
uint8_t *current_node_data_space_p = _recordset_p->get_node_data_space (current_node_p);
|
||||
size_t left_in_node = node_data_space_size - (size_t)(_current_pos_p - current_node_data_space_p);
|
||||
|
||||
JERRY_ASSERT (_current_offset + size <= record_size);
|
||||
|
||||
/*
|
||||
* Read the data and increase the current position pointer.
|
||||
*/
|
||||
if (left_in_node >= size)
|
||||
{
|
||||
/* all data is placed inside single node */
|
||||
if (access_type == ACCESS_READ)
|
||||
{
|
||||
memcpy (data, _current_pos_p, size);
|
||||
}
|
||||
else if (access_type == ACCESS_WRITE)
|
||||
{
|
||||
memcpy (_current_pos_p, data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (access_type == ACCESS_SKIP);
|
||||
|
||||
if (left_in_node > size)
|
||||
{
|
||||
_current_pos_p += size;
|
||||
}
|
||||
else if (_current_offset + size < record_size)
|
||||
{
|
||||
current_node_p = _recordset_p->_chunk_list.get_next (current_node_p);
|
||||
JERRY_ASSERT (current_node_p);
|
||||
_current_pos_p = _recordset_p->get_node_data_space (current_node_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (_current_offset + size == record_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* data is distributed between two nodes */
|
||||
size_t first_chunk_size = node_data_space_size - (size_t) (_current_pos_p - current_node_data_space_p);
|
||||
|
||||
if (access_type == ACCESS_READ)
|
||||
{
|
||||
memcpy (data, _current_pos_p, first_chunk_size);
|
||||
}
|
||||
else if (access_type == ACCESS_WRITE)
|
||||
{
|
||||
memcpy (_current_pos_p, data, first_chunk_size);
|
||||
}
|
||||
|
||||
rcs_chunked_list_t::node_t *next_node_p = _recordset_p->_chunk_list.get_next (current_node_p);
|
||||
JERRY_ASSERT (next_node_p != NULL);
|
||||
uint8_t *next_node_data_space_p = _recordset_p->get_node_data_space (next_node_p);
|
||||
|
||||
if (access_type == ACCESS_READ)
|
||||
{
|
||||
memcpy ((uint8_t *)data + first_chunk_size, next_node_data_space_p, size - first_chunk_size);
|
||||
}
|
||||
else if (access_type == ACCESS_WRITE)
|
||||
{
|
||||
memcpy (next_node_data_space_p, (uint8_t *)data + first_chunk_size, size - first_chunk_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (access_type == ACCESS_SKIP);
|
||||
|
||||
_current_pos_p = next_node_data_space_p + size - first_chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we reached the end */
|
||||
if (access_type == ACCESS_SKIP)
|
||||
{
|
||||
_current_offset += size;
|
||||
JERRY_ASSERT (_current_offset <= record_size);
|
||||
|
||||
if (_current_offset == record_size)
|
||||
{
|
||||
_current_pos_p = NULL;
|
||||
_current_offset = 0;
|
||||
}
|
||||
}
|
||||
} /* rcs_record_iterator_t::access */
|
||||
|
||||
/**
|
||||
* Get size of the free record
|
||||
*/
|
||||
size_t
|
||||
rcs_free_record_t::get_size (void)
|
||||
const
|
||||
{
|
||||
return get_field (_length_field_pos, _length_field_width) * RCS_DYN_STORAGE_LENGTH_UNIT;
|
||||
} /* rcs_free_record_t::get_size */
|
||||
|
||||
/**
|
||||
* Set size of the free record
|
||||
*/
|
||||
void
|
||||
rcs_free_record_t::set_size (size_t size) /**< size to set */
|
||||
{
|
||||
JERRY_ASSERT (JERRY_ALIGNUP (size, RCS_DYN_STORAGE_LENGTH_UNIT) == size);
|
||||
|
||||
set_field (_length_field_pos, _length_field_width, size >> RCS_DYN_STORAGE_LENGTH_UNIT_LOG);
|
||||
} /* rcs_free_record_t::set_size */
|
||||
|
||||
/**
|
||||
* Get previous record for the free record
|
||||
*/
|
||||
rcs_record_t*
|
||||
rcs_free_record_t::get_prev (void)
|
||||
const
|
||||
{
|
||||
return get_pointer (_prev_field_pos, _prev_field_width);
|
||||
} /* rcs_free_record_t::get_prev */
|
||||
|
||||
/**
|
||||
* Set previous record for the free record
|
||||
*/
|
||||
void
|
||||
rcs_free_record_t::set_prev (rcs_record_t* prev_rec_p) /**< previous record to set */
|
||||
{
|
||||
set_pointer (_prev_field_pos, _prev_field_width, prev_rec_p);
|
||||
} /* rcs_free_record_t::set_prev */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -1,383 +0,0 @@
|
||||
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef RCS_RECORDSET_H
|
||||
#define RCS_RECORDSET_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jrt.h"
|
||||
#include "jrt-bit-fields.h"
|
||||
#include "mem-allocator.h"
|
||||
#include "rcs-chunked-list.h"
|
||||
|
||||
/** \addtogroup recordset Recordset
|
||||
* @{
|
||||
*
|
||||
* Non-contiguous container abstraction with iterator.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Logarithm of a dynamic storage unit alignment
|
||||
*/
|
||||
#define RCS_DYN_STORAGE_LENGTH_UNIT_LOG (2u)
|
||||
|
||||
/**
|
||||
* Unit of length
|
||||
*/
|
||||
#define RCS_DYN_STORAGE_LENGTH_UNIT ((size_t) (1ull << RCS_DYN_STORAGE_LENGTH_UNIT_LOG))
|
||||
|
||||
/**
|
||||
* Dynamic storage
|
||||
*
|
||||
* Note:
|
||||
* Static C++ constructors / desctructors are supposed to be not supported.
|
||||
* So, initialization / destruction is implemented through init / finalize
|
||||
* static functions.
|
||||
*/
|
||||
class rcs_recordset_t
|
||||
{
|
||||
public:
|
||||
/* Constructor */
|
||||
void init (void)
|
||||
{
|
||||
_chunk_list.init ();
|
||||
|
||||
JERRY_ASSERT (get_node_data_space_size () % RCS_DYN_STORAGE_LENGTH_UNIT == 0);
|
||||
} /* init */
|
||||
|
||||
/* Destructor */
|
||||
void finalize (void)
|
||||
{
|
||||
_chunk_list.free ();
|
||||
} /* finalize */
|
||||
|
||||
/* Free memory occupied by the dynamic storage */
|
||||
void cleanup (void)
|
||||
{
|
||||
_chunk_list.cleanup ();
|
||||
} /* cleanup */
|
||||
|
||||
/**
|
||||
* Record type
|
||||
*/
|
||||
class record_t
|
||||
{
|
||||
public:
|
||||
typedef uint8_t type_t;
|
||||
|
||||
type_t get_type (void) const;
|
||||
void set_type (type_t);
|
||||
|
||||
/**
|
||||
* Dynamic storage-specific extended compressed pointer
|
||||
*
|
||||
* Note:
|
||||
* the pointer can represent addresses aligned by RCS_DYN_STORAGE_LENGTH_UNIT,
|
||||
* while mem_cpointer_t can only represent addresses aligned by MEM_ALIGNMENT.
|
||||
*/
|
||||
struct cpointer_t
|
||||
{
|
||||
static const uint32_t bit_field_width = MEM_CP_WIDTH + MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
mem_cpointer_t base_cp : MEM_CP_WIDTH; /**< pointer to base of addressed area */
|
||||
#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG
|
||||
uint16_t ext : (MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_LENGTH_UNIT_LOG); /**< extension of the basic
|
||||
* compressed pointer
|
||||
* used for more detailed
|
||||
* addressing */
|
||||
#endif /* MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_LENGTH_UNIT_LOG */
|
||||
} value;
|
||||
uint16_t packed_value;
|
||||
};
|
||||
|
||||
static cpointer_t compress (record_t *);
|
||||
static record_t *decompress (cpointer_t);
|
||||
|
||||
static cpointer_t null_cp ();
|
||||
|
||||
static const int conval = 3;
|
||||
};
|
||||
|
||||
private:
|
||||
/**
|
||||
* Offset of 'type' field, in bits
|
||||
*/
|
||||
static constexpr uint32_t _type_field_pos = 0u;
|
||||
|
||||
/**
|
||||
* Width of 'type' field, in bits
|
||||
*/
|
||||
static constexpr uint32_t _type_field_width = 4u;
|
||||
|
||||
protected:
|
||||
void check_this (void) const;
|
||||
|
||||
uint32_t get_field (uint32_t, uint32_t) const;
|
||||
void set_field (uint32_t, uint32_t, size_t);
|
||||
|
||||
record_t *get_pointer (uint32_t, uint32_t) const;
|
||||
void set_pointer (uint32_t, uint32_t, record_t *);
|
||||
|
||||
/**
|
||||
* Offset of a derived record's fields, in bits
|
||||
*/
|
||||
static constexpr uint32_t _fields_offset_begin = _type_field_pos + _type_field_width;
|
||||
};
|
||||
|
||||
record_t *get_first (void);
|
||||
record_t *get_next (record_t *);
|
||||
|
||||
private:
|
||||
friend class rcs_record_iterator_t;
|
||||
|
||||
/**
|
||||
* Type identifier for free record
|
||||
*/
|
||||
static const record_t::type_t _free_record_type_id = 0;
|
||||
|
||||
/**
|
||||
* Chunked list used for memory allocation
|
||||
*/
|
||||
rcs_chunked_list_t _chunk_list;
|
||||
|
||||
void alloc_record_in_place (record_t *, size_t, record_t *);
|
||||
|
||||
void init_free_record (record_t *, size_t, record_t *);
|
||||
bool is_record_free (record_t *);
|
||||
|
||||
uint8_t *get_node_data_space (rcs_chunked_list_t::node_t *) const;
|
||||
static size_t get_node_data_space_size (void);
|
||||
protected:
|
||||
/**
|
||||
* First type identifier that can be used for storage-specific record types
|
||||
*/
|
||||
static const record_t::type_t _first_type_id = _free_record_type_id + 1;
|
||||
|
||||
/**
|
||||
* Allocate new record of specified type
|
||||
*
|
||||
* @return pointer to the new record
|
||||
*/
|
||||
template<
|
||||
typename T, /**< type of record structure */
|
||||
typename ... SizeArgs> /**< type of arguments of T::size */
|
||||
T *alloc_record (record_t::type_t type, /**< record's type identifier */
|
||||
SizeArgs ... size_args) /**< arguments of T::size */
|
||||
{
|
||||
JERRY_ASSERT (type >= _first_type_id);
|
||||
|
||||
size_t size = T::size (size_args...);
|
||||
|
||||
record_t *prev_rec_p;
|
||||
T *rec_p = static_cast<T*> (alloc_space_for_record (size, &prev_rec_p));
|
||||
|
||||
rec_p->set_type (type);
|
||||
rec_p->set_size (size);
|
||||
rec_p->set_prev (prev_rec_p);
|
||||
|
||||
assert_state_is_correct ();
|
||||
|
||||
return rec_p;
|
||||
} /* alloc_record */
|
||||
|
||||
record_t *alloc_space_for_record (size_t, record_t **);
|
||||
void free_record (record_t *);
|
||||
|
||||
virtual record_t *get_prev (record_t *);
|
||||
|
||||
virtual void set_prev (record_t *, record_t *);
|
||||
|
||||
virtual size_t get_record_size (record_t *);
|
||||
|
||||
void assert_state_is_correct (void);
|
||||
}; /* rcs_recordset_t */
|
||||
|
||||
/**
|
||||
* Record type
|
||||
*/
|
||||
typedef rcs_recordset_t::record_t rcs_record_t;
|
||||
|
||||
/**
|
||||
* Recordset-specific compressed pointer type
|
||||
*/
|
||||
typedef rcs_record_t::cpointer_t rcs_cpointer_t;
|
||||
|
||||
/**
|
||||
* Record iterator
|
||||
*/
|
||||
class rcs_record_iterator_t
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
rcs_record_iterator_t (rcs_recordset_t *rcs_p, /**< recordset */
|
||||
rcs_record_t *rec_p) /**< record which should belong to the recordset */
|
||||
{
|
||||
_record_start_p = rec_p;
|
||||
_recordset_p = rcs_p;
|
||||
|
||||
reset ();
|
||||
} /* rcs_record_iterator_t */
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
rcs_record_iterator_t (rcs_recordset_t *rcs_p, /**< recordset */
|
||||
rcs_cpointer_t rec_ext_cp) /**< compressed pointer to the record */
|
||||
{
|
||||
_record_start_p = rcs_cpointer_t::decompress (rec_ext_cp);
|
||||
_recordset_p = rcs_p;
|
||||
|
||||
reset ();
|
||||
} /* rcs_record_iterator_t */
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Types of access
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ACCESS_WRITE, /**< If access_type == ACCESS_WRITE,
|
||||
* write 'size' bytes from 'data' buffer to the record. */
|
||||
ACCESS_READ, /**< If access_type == ACCESS_READ,
|
||||
* read 'size' bytes from the record and write to the 'data' buffer. */
|
||||
ACCESS_SKIP /**< If access_type == ACCESS_SKIP,
|
||||
* increment current position so that 'size' bytes would be skipped. */
|
||||
} access_t;
|
||||
|
||||
void access (access_t, void *, size_t);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Read value of type T from the record.
|
||||
* After reading iterator doesn't change its position.
|
||||
*
|
||||
* @return read value
|
||||
*/
|
||||
template<typename T> T read (void)
|
||||
{
|
||||
T data;
|
||||
access (ACCESS_READ, &data, sizeof (T));
|
||||
return data;
|
||||
} /* read */
|
||||
|
||||
/**
|
||||
* Write value of type T to the record.
|
||||
* After writing iterator doesn't change its position.
|
||||
*/
|
||||
template<typename T> void write (T value) /**< value to write */
|
||||
{
|
||||
access (ACCESS_WRITE, &value, sizeof (T));
|
||||
} /* write */
|
||||
|
||||
/**
|
||||
* Increment current position to skip T value in the record.
|
||||
*/
|
||||
template<typename T> void skip ()
|
||||
{
|
||||
access (ACCESS_SKIP, NULL, sizeof (T));
|
||||
} /* skip */
|
||||
|
||||
/**
|
||||
* Increment current position to skip 'size' bytes.
|
||||
*/
|
||||
void skip (size_t size) /**< number of bytes to skip */
|
||||
{
|
||||
if (size)
|
||||
{
|
||||
access (ACCESS_SKIP, NULL, size);
|
||||
}
|
||||
} /* skip */
|
||||
|
||||
/**
|
||||
* Check if the end of the record was reached.
|
||||
*
|
||||
* @return true if the whole record was iterated
|
||||
* false otherwise
|
||||
*/
|
||||
bool finished ()
|
||||
{
|
||||
return _current_pos_p == NULL;
|
||||
} /* finished */
|
||||
|
||||
/**
|
||||
* Reset the iterator, so that it points to the beginning of the record
|
||||
*/
|
||||
void reset ()
|
||||
{
|
||||
_current_pos_p = (uint8_t *)_record_start_p;
|
||||
_current_offset = 0;
|
||||
} /* reset */
|
||||
|
||||
private:
|
||||
rcs_record_t *_record_start_p; /**< start of current record */
|
||||
uint8_t *_current_pos_p; /**< pointer to current offset in current record */
|
||||
size_t _current_offset; /**< current offset */
|
||||
rcs_recordset_t *_recordset_p; /**< recordset containing the record */
|
||||
}; /* rcs_record_iterator_t */
|
||||
|
||||
/**
|
||||
* Free record layout description
|
||||
*/
|
||||
class rcs_free_record_t : public rcs_record_t
|
||||
{
|
||||
public:
|
||||
size_t get_size (void) const;
|
||||
void set_size (size_t);
|
||||
|
||||
rcs_record_t *get_prev (void) const;
|
||||
void set_prev (rcs_record_t *);
|
||||
private:
|
||||
/**
|
||||
* Offset of 'length' field, in bits
|
||||
*/
|
||||
static constexpr uint32_t _length_field_pos = _fields_offset_begin;
|
||||
|
||||
/**
|
||||
* Width of 'length' field, in bits
|
||||
*/
|
||||
static constexpr uint32_t _length_field_width = 14u - RCS_DYN_STORAGE_LENGTH_UNIT_LOG;
|
||||
|
||||
/**
|
||||
* Offset of 'previous record' field, in bits
|
||||
*/
|
||||
static constexpr uint32_t _prev_field_pos = _length_field_pos + _length_field_width;
|
||||
|
||||
/**
|
||||
* Width of 'previous record' field, in bits
|
||||
*/
|
||||
static constexpr uint32_t _prev_field_width = rcs_cpointer_t::bit_field_width;
|
||||
|
||||
/**
|
||||
* Free record should be be placeable at any free space unit of recordset,
|
||||
* and so its size should be less than minimal size of a free space unit
|
||||
* that is RCS_DYN_STORAGE_LENGTH_UNIT bytes.
|
||||
*/
|
||||
JERRY_STATIC_ASSERT (_prev_field_pos + _prev_field_width <= RCS_DYN_STORAGE_LENGTH_UNIT * JERRY_BITSINBYTE);
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#endif /* RCS_RECORDSET_H */
|
||||
Reference in New Issue
Block a user