Add literal storage, literal_t type and functions for its processing.
JerryScript-DCO-1.0-Signed-off-by: Evgeny Gavrin e.gavrin@samsung.com JerryScript-DCO-1.0-Signed-off-by: Andrey Shitov a.shitov@samsung.com
This commit is contained in:
@@ -93,6 +93,7 @@ project (JerryCore CXX C ASM)
|
||||
# Include directories
|
||||
set(INCLUDE_CORE
|
||||
${CMAKE_SOURCE_DIR}/jerry-core
|
||||
${CMAKE_SOURCE_DIR}/jerry-core/lit
|
||||
${CMAKE_SOURCE_DIR}/jerry-core/rcs
|
||||
${CMAKE_SOURCE_DIR}/jerry-core/mem
|
||||
${CMAKE_SOURCE_DIR}/jerry-core/vm
|
||||
@@ -110,6 +111,7 @@ project (JerryCore CXX C ASM)
|
||||
# Sources
|
||||
# Jerry core
|
||||
file(GLOB SOURCE_CORE_API *.cpp)
|
||||
file(GLOB SOURCE_CORE_LIT lit/*.cpp)
|
||||
file(GLOB SOURCE_CORE_RCS rcs/*.cpp)
|
||||
file(GLOB SOURCE_CORE_MEM mem/*.cpp)
|
||||
file(GLOB SOURCE_CORE_VM vm/*.cpp)
|
||||
@@ -123,6 +125,7 @@ project (JerryCore CXX C ASM)
|
||||
set(SOURCE_CORE
|
||||
jerry.cpp
|
||||
${SOURCE_CORE_API}
|
||||
${SOURCE_CORE_LIT}
|
||||
${SOURCE_CORE_RCS}
|
||||
${SOURCE_CORE_MEM}
|
||||
${SOURCE_CORE_VM}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "config.h"
|
||||
#include "jrt.h"
|
||||
#include "mem-allocator.h"
|
||||
#include "rcs-recordset.h"
|
||||
|
||||
/** \addtogroup compressedpointer Compressed pointer
|
||||
* @{
|
||||
@@ -757,11 +758,20 @@ typedef enum
|
||||
} ecma_string_container_t;
|
||||
|
||||
FIXME (Move to library that should define the type (literal.h /* ? */))
|
||||
/**
|
||||
* Literal and compressed pointer to literal
|
||||
*/
|
||||
typedef rcs_record_t *literal_t;
|
||||
typedef rcs_cpointer_t lit_cpointer_t;
|
||||
|
||||
/**
|
||||
* Index in literal table
|
||||
*
|
||||
* FIXME: Remove after switching to literal storage
|
||||
*/
|
||||
typedef uint32_t literal_index_t;
|
||||
|
||||
|
||||
/**
|
||||
* Identifiers of ECMA and implementation-defined magic string constants
|
||||
*/
|
||||
|
||||
@@ -214,4 +214,16 @@ extern void __noreturn jerry_fatal (jerry_fatal_code_t code);
|
||||
#define JERRY_MIN(v1, v2) ((v1 < v2) ? v1 : v2)
|
||||
#define JERRY_MAX(v1, v2) ((v1 < v2) ? v2 : v1)
|
||||
|
||||
/**
|
||||
* Placement new operator (constructs an object on a pre-allocated buffer)
|
||||
*
|
||||
* Our version of the libc library doesn't support calling the constructors and destructors of the static variables.
|
||||
* It is proposed to use placement new operator. Generally it is available via #include <new>,
|
||||
* To fix the unavailability of the header in some configurations placement new operator is implemented here.
|
||||
*/
|
||||
inline void* operator new (size_t, void* where)
|
||||
{
|
||||
return where;
|
||||
} /* operator new */
|
||||
|
||||
#endif /* !JERRY_GLOBALS_H */
|
||||
|
||||
@@ -0,0 +1,460 @@
|
||||
/* 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 "lit-literal-storage.h"
|
||||
#include "ecma-helpers.h"
|
||||
|
||||
/**
|
||||
* Literal storage
|
||||
* As our libc library doesn't call constructors of static variables, lit_storage is initialized
|
||||
* in lit_init function by placement new operator.
|
||||
*/
|
||||
lit_literal_storage_t lit_storage;
|
||||
|
||||
/**
|
||||
* Get pointer to the previous record inside the literal storage
|
||||
*
|
||||
* @return pointer to the previous record of NULL if this is the first record ('prev' field in the header)
|
||||
*/
|
||||
rcs_record_t *
|
||||
lit_charset_record_t::get_prev () const
|
||||
{
|
||||
rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage, (rcs_record_t *)this);
|
||||
it.skip (RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
|
||||
cpointer_t cpointer;
|
||||
cpointer.packed_value = it.read<uint16_t> ();
|
||||
|
||||
return cpointer_t::decompress (cpointer);
|
||||
} /* lit_charset_record_t::get_prev */
|
||||
|
||||
/**
|
||||
* Set the pointer to the previous record inside the literal storage (sets 'prev' field in the header)
|
||||
*/
|
||||
void
|
||||
lit_charset_record_t::set_prev (rcs_record_t *prev_rec_p) /**< pointer to the record to set as previous */
|
||||
{
|
||||
rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage, (rcs_record_t *)this);
|
||||
it.skip (RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
|
||||
it.write<uint16_t> (cpointer_t::compress (prev_rec_p).packed_value);
|
||||
} /* lit_charset_record_t::set_prev */
|
||||
|
||||
/**
|
||||
* Set the charset of the record
|
||||
*/
|
||||
void
|
||||
lit_charset_record_t::set_charset (const ecma_char_t *str, /**< buffer containing characters to set */
|
||||
size_t size) /**< size of the buffer in bytes */
|
||||
{
|
||||
JERRY_ASSERT (header_size () + size == get_size () - get_alignment_bytes_count ());
|
||||
|
||||
rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage, (rcs_record_t *)this);
|
||||
it.skip (header_size ());
|
||||
|
||||
for (size_t i = 0; i < get_length (); ++i)
|
||||
{
|
||||
it.write<ecma_char_t> (str[i]);
|
||||
it.skip<ecma_char_t> ();
|
||||
}
|
||||
} /* lit_charset_record_t::set_charset */
|
||||
|
||||
/**
|
||||
* Get the characters which are stored to the record
|
||||
*
|
||||
* @return number of code units written to the buffer
|
||||
*/
|
||||
ecma_length_t
|
||||
lit_charset_record_t::get_charset (ecma_char_t *buff, /**< output buffer */
|
||||
size_t size) /**< size of the output buffer in bytes */
|
||||
{
|
||||
JERRY_ASSERT (buff && size >= sizeof (ecma_char_t));
|
||||
|
||||
rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage, (rcs_record_t *)this);
|
||||
it.skip (header_size ());
|
||||
ecma_length_t len = get_length ();
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len && size > sizeof (ecma_char_t); ++i)
|
||||
{
|
||||
buff[i] = it.read<ecma_char_t> ();
|
||||
it.skip<ecma_char_t> ();
|
||||
size -= sizeof (ecma_char_t);
|
||||
}
|
||||
|
||||
return (ecma_length_t) i;
|
||||
} /* lit_charset_record_t::get_charset */
|
||||
|
||||
/**
|
||||
* Compares characters from the record to the string
|
||||
*
|
||||
* @return 0 if strings are equal
|
||||
* -1 if str2 is greater
|
||||
* 1 if str2 is less
|
||||
*/
|
||||
int
|
||||
lit_charset_record_t::compare_zt (const ecma_char_t *str_to_compare_with, /**< buffer with string to compare */
|
||||
size_t length) /**< length of the string in buffer str2 */
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (get_length () == 0)
|
||||
{
|
||||
if (str_to_compare_with != NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (str_to_compare_with == NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
rcs_record_iterator_t it_this (&lit_storage, this);
|
||||
|
||||
it_this.skip (header_size ());
|
||||
|
||||
for (i = 0; i < get_length () && i < length; i++)
|
||||
{
|
||||
ecma_char_t chr = it_this.read<ecma_char_t> ();
|
||||
|
||||
if (chr > str_to_compare_with[i])
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if (chr < str_to_compare_with[i])
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
it_this.skip<ecma_char_t> ();
|
||||
}
|
||||
|
||||
if (i < length)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* lit_charset_record_t::compare_zt */
|
||||
|
||||
/**
|
||||
* Compares two lit_charset_record_t records for equality
|
||||
*
|
||||
* @return true if strings inside records are equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
lit_charset_record_t::equal (lit_charset_record_t *rec) /**< charset record to compare with */
|
||||
{
|
||||
if (get_length () != rec->get_length ())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
rcs_record_iterator_t it_this (&lit_storage, this);
|
||||
rcs_record_iterator_t it_record (&lit_storage, rec);
|
||||
|
||||
it_this.skip (header_size ());
|
||||
it_record.skip (rec->header_size ());
|
||||
|
||||
for (ecma_length_t i = 0; i < get_length (); i++)
|
||||
{
|
||||
if (it_this.read<ecma_char_t> () != it_record.read<ecma_char_t> ())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
it_this.skip<ecma_char_t> ();
|
||||
it_record.skip<ecma_char_t> ();
|
||||
}
|
||||
|
||||
return true;
|
||||
} /* lit_charset_record_t::equal */
|
||||
|
||||
/**
|
||||
* Compares this lit_charset_record_t records with zero-terminated string for equality
|
||||
*
|
||||
* @return true if compared instances are equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
lit_charset_record_t::equal_zt (const ecma_char_t *str) /**< zero-terminated string */
|
||||
{
|
||||
return equal_non_zt (str, ecma_zt_string_length (str));
|
||||
} /* lit_charset_record_t::equal_zt */
|
||||
|
||||
/**
|
||||
* Compare this lit_charset_record_t record with string (which could contain '\0' characters) for equality
|
||||
*
|
||||
* @return true if compared instances are equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
lit_charset_record_t::equal_non_zt (const ecma_char_t *str, /**< string to compare with */
|
||||
ecma_length_t len) /**< length of the string */
|
||||
{
|
||||
rcs_record_iterator_t it_this (&lit_storage, this);
|
||||
|
||||
it_this.skip (header_size ());
|
||||
|
||||
for (ecma_length_t i = 0; i < get_length () && i < len; i++)
|
||||
{
|
||||
if (it_this.read<ecma_char_t> () != str[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
it_this.skip<ecma_char_t> ();
|
||||
}
|
||||
|
||||
return get_length () == len;
|
||||
} /* lit_charset_record_t::equal_non_zt */
|
||||
|
||||
/**
|
||||
* Create charset record in the literal storage
|
||||
*
|
||||
* @return pointer to the created record
|
||||
*/
|
||||
lit_charset_record_t *
|
||||
lit_literal_storage_t::create_charset_record (const ecma_char_t *str, /**< string to be placed in the record */
|
||||
size_t buf_size) /**< size in bytes of the buffer which holds the
|
||||
* string */
|
||||
{
|
||||
const size_t alignment = lit_charset_record_t::size (buf_size) - (lit_charset_record_t::header_size () + buf_size);
|
||||
|
||||
lit_charset_record_t *ret = alloc_record<lit_charset_record_t, size_t> (LIT_STR, buf_size);
|
||||
|
||||
ret->set_alignment_bytes_count (alignment);
|
||||
ret->set_charset (str, buf_size);
|
||||
ret->set_hash (ecma_chars_buffer_calc_hash_last_chars (str, ret->get_length ()));
|
||||
|
||||
return ret;
|
||||
} /* lit_literal_storage_t::create_charset_record */
|
||||
|
||||
/**
|
||||
* Create magic string record in the literal storage
|
||||
*
|
||||
* @return pointer to the created record
|
||||
*/
|
||||
lit_magic_record_t *
|
||||
lit_literal_storage_t::create_magic_record (ecma_magic_string_id_t id) /**< id of a magic string */
|
||||
{
|
||||
lit_magic_record_t *ret = alloc_record<lit_magic_record_t> (LIT_MAGIC_STR);
|
||||
|
||||
ret->set_magic_str_id (id);
|
||||
|
||||
return ret;
|
||||
} /* lit_literal_storage_t::create_magic_record */
|
||||
|
||||
/**
|
||||
* Create number record in the literal storage
|
||||
*
|
||||
* @return pointer to the created record
|
||||
*/
|
||||
lit_number_record_t *
|
||||
lit_literal_storage_t::create_number_record (ecma_number_t num) /**< number */
|
||||
{
|
||||
lit_number_record_t *ret = alloc_record<lit_number_record_t> (LIT_NUMBER);
|
||||
rcs_record_iterator_t it_this (this, ret);
|
||||
|
||||
it_this.skip (ret->header_size ());
|
||||
it_this.write<ecma_number_t> (num);
|
||||
|
||||
return ret;
|
||||
} /* lit_literal_storage_t::create_number_record */
|
||||
|
||||
/**
|
||||
* Dump the contents of the literal storage
|
||||
*/
|
||||
void
|
||||
lit_literal_storage_t::dump ()
|
||||
{
|
||||
printf ("LITERALS:\n");
|
||||
|
||||
for (rcs_record_t *rec_p = lit_storage.get_first (); rec_p != NULL; rec_p = lit_storage.get_next (rec_p))
|
||||
{
|
||||
printf ("%p ", rec_p);
|
||||
printf ("[%3zu] ", get_record_size (rec_p));
|
||||
|
||||
switch (rec_p->get_type ())
|
||||
{
|
||||
case LIT_STR:
|
||||
{
|
||||
lit_charset_record_t *lit_p = static_cast<lit_charset_record_t *> (rec_p);
|
||||
rcs_record_iterator_t it_this (this, rec_p);
|
||||
|
||||
it_this.skip (lit_charset_record_t::header_size ());
|
||||
|
||||
for (size_t i = 0; i < lit_p->get_length (); ++i)
|
||||
{
|
||||
printf ("%c", it_this.read<ecma_char_t> ());
|
||||
it_this.skip<ecma_char_t> ();
|
||||
}
|
||||
|
||||
printf (" : STRING");
|
||||
|
||||
break;
|
||||
}
|
||||
case LIT_MAGIC_STR:
|
||||
{
|
||||
lit_magic_record_t *lit_p = static_cast<lit_magic_record_t *> (rec_p);
|
||||
|
||||
printf ("%s : MAGIC STRING", ecma_get_magic_string_zt (lit_p->get_magic_str_id ()));
|
||||
printf (" [id=%d] ", lit_p->get_magic_str_id ());
|
||||
|
||||
break;
|
||||
}
|
||||
case LIT_NUMBER:
|
||||
{
|
||||
lit_number_record_t *lit_p = static_cast<lit_number_record_t *> (rec_p);
|
||||
|
||||
if (ecma_number_is_nan (lit_p->get_number ()))
|
||||
{
|
||||
printf ("%s : NUMBER", "NaN");
|
||||
}
|
||||
else
|
||||
{
|
||||
ecma_char_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
|
||||
ecma_number_to_zt_string (lit_p->get_number (), buff, ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER);
|
||||
printf ("%s : NUMBER", buff);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
printf (" : EMPTY RECORD");
|
||||
}
|
||||
}
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
} /* lit_literal_storage_t::dump */
|
||||
|
||||
/**
|
||||
* Get previous record in the literal storage
|
||||
*
|
||||
* @return pointer to the previous record relative to rec_p, or NULL if rec_p is the first record in the storage
|
||||
*/
|
||||
rcs_record_t *
|
||||
lit_literal_storage_t::get_prev (rcs_record_t *rec_p) /**< record, relative to which previous should be found */
|
||||
{
|
||||
switch (rec_p->get_type ())
|
||||
{
|
||||
case LIT_STR:
|
||||
{
|
||||
return (static_cast<lit_charset_record_t *> (rec_p))->get_prev ();
|
||||
}
|
||||
case LIT_MAGIC_STR:
|
||||
{
|
||||
return (static_cast<lit_magic_record_t *> (rec_p))->get_prev ();
|
||||
}
|
||||
case LIT_NUMBER:
|
||||
{
|
||||
return (static_cast<lit_number_record_t *> (rec_p))->get_prev ();
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_ASSERT (rec_p->get_type () < _first_type_id);
|
||||
|
||||
return rcs_recordset_t::get_prev (rec_p);
|
||||
}
|
||||
}
|
||||
} /* lit_literal_storage_t::get_prev */
|
||||
|
||||
/**
|
||||
* Set pointer to the previous record
|
||||
*/
|
||||
void
|
||||
lit_literal_storage_t::set_prev (rcs_record_t *rec_p, /**< record to modify */
|
||||
rcs_record_t *prev_rec_p) /**< record which should be set as previous */
|
||||
{
|
||||
switch (rec_p->get_type ())
|
||||
{
|
||||
case LIT_STR:
|
||||
{
|
||||
return (static_cast<lit_charset_record_t *> (rec_p))->set_prev (prev_rec_p);
|
||||
}
|
||||
case LIT_MAGIC_STR:
|
||||
{
|
||||
return (static_cast<lit_magic_record_t *> (rec_p))->set_prev (prev_rec_p);
|
||||
}
|
||||
case LIT_NUMBER:
|
||||
{
|
||||
return (static_cast<lit_number_record_t *> (rec_p))->set_prev (prev_rec_p);
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_ASSERT (rec_p->get_type () < _first_type_id);
|
||||
|
||||
return rcs_recordset_t::set_prev (rec_p, prev_rec_p);
|
||||
}
|
||||
}
|
||||
} /* lit_literal_storage_t::set_prev */
|
||||
|
||||
/**
|
||||
* Get size of a record
|
||||
*
|
||||
* @return size of a record in bytes
|
||||
*/
|
||||
size_t
|
||||
lit_literal_storage_t::get_record_size (rcs_record_t* rec_p) /**< pointer to a record */
|
||||
{
|
||||
switch (rec_p->get_type ())
|
||||
{
|
||||
case LIT_STR:
|
||||
{
|
||||
return (static_cast<lit_charset_record_t *> (rec_p))->get_size ();
|
||||
}
|
||||
case LIT_MAGIC_STR:
|
||||
{
|
||||
return lit_magic_record_t::size ();
|
||||
}
|
||||
case LIT_NUMBER:
|
||||
{
|
||||
return lit_number_record_t::size ();
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_ASSERT (rec_p->get_type () < _first_type_id);
|
||||
|
||||
return rcs_recordset_t::get_record_size (rec_p);
|
||||
}
|
||||
}
|
||||
} /* lit_literal_storage_t::get_record_size */
|
||||
|
||||
template void rcs_record_iterator_t::skip<ecma_char_t> ();
|
||||
template void rcs_record_iterator_t::skip<uint16_t> ();
|
||||
template void rcs_record_iterator_t::skip<uint32_t> ();
|
||||
|
||||
template void rcs_record_iterator_t::write<ecma_char_t> (ecma_char_t);
|
||||
template ecma_char_t rcs_record_iterator_t::read<ecma_char_t> ();
|
||||
|
||||
template void rcs_record_iterator_t::write<ecma_number_t> (ecma_number_t);
|
||||
template ecma_number_t rcs_record_iterator_t::read<ecma_number_t> ();
|
||||
|
||||
template void rcs_record_iterator_t::write<uint16_t> (uint16_t);
|
||||
template uint16_t rcs_record_iterator_t::read<uint16_t> ();
|
||||
|
||||
template lit_charset_record_t *rcs_recordset_t::alloc_record<lit_charset_record_t> (rcs_record_t::type_t type,
|
||||
size_t size);
|
||||
template lit_magic_record_t *rcs_recordset_t::alloc_record<lit_magic_record_t> (rcs_record_t::type_t type);
|
||||
template lit_number_record_t *rcs_recordset_t::alloc_record<lit_number_record_t> (rcs_record_t::type_t type);
|
||||
@@ -0,0 +1,434 @@
|
||||
/* 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 LIT_LITERAL_STORAGE_H
|
||||
#define LIT_LITERAL_STORAGE_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
#include "rcs-recordset.h"
|
||||
|
||||
class lit_literal_storage_t;
|
||||
extern lit_literal_storage_t lit_storage;
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* --------------------------------------
|
||||
*/
|
||||
class lit_charset_record_t : public rcs_record_t
|
||||
{
|
||||
friend class rcs_recordset_t;
|
||||
friend class lit_literal_storage_t;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Calculate the size that record will occupy inside the storage
|
||||
*
|
||||
* @return size of the record in bytes
|
||||
*/
|
||||
static size_t
|
||||
size (size_t size) /**< size of the charset buffer */
|
||||
{
|
||||
return JERRY_ALIGNUP (size + header_size (), RCS_DYN_STORAGE_LENGTH_UNIT);
|
||||
} /* size */
|
||||
|
||||
/**
|
||||
* Get the size of the header part of the record
|
||||
*
|
||||
* @return size of the header in bytes
|
||||
*/
|
||||
static size_t
|
||||
header_size ()
|
||||
{
|
||||
return _header_size;
|
||||
} /* header_size */
|
||||
|
||||
/**
|
||||
* 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 (the value of the 'alignment' field in the header)
|
||||
*/
|
||||
size_t
|
||||
get_alignment_bytes_count () const
|
||||
{
|
||||
return get_field (_alignment_field_pos, _alignment_field_width);
|
||||
} /* get_alignment_bytes_count */
|
||||
|
||||
/**
|
||||
* Set the count of the alignment bytes at the end of record (the value of the 'alignment' field in the header)
|
||||
*/
|
||||
void
|
||||
set_alignment_bytes_count (size_t count) /**< count of the alignment bytes */
|
||||
{
|
||||
JERRY_ASSERT (count <= RCS_DYN_STORAGE_ALIGNMENT);
|
||||
set_field (_alignment_field_pos, _alignment_field_width, count);
|
||||
} /* set_alignment_bytes_count */
|
||||
|
||||
/**
|
||||
* Get hash value of the record's charset.
|
||||
*
|
||||
* @return hash value of the string (the value of the 'hash' field in the header)
|
||||
*/
|
||||
ecma_string_hash_t
|
||||
get_hash () const
|
||||
{
|
||||
return (ecma_string_hash_t) get_field (_hash_field_pos, _hash_field_width);
|
||||
} /* get_hash */
|
||||
|
||||
/**
|
||||
* Get the length of the string, which is contained inside the record
|
||||
*
|
||||
* @return length of the string (count of the ecma_char_t characters inside the charset)
|
||||
*/
|
||||
ecma_length_t
|
||||
get_length () const
|
||||
{
|
||||
return (ecma_length_t) ((get_size () - header_size () - get_alignment_bytes_count ()) / sizeof (ecma_char_t));
|
||||
} /* get_length */
|
||||
|
||||
/**
|
||||
* Get the size of the record
|
||||
*
|
||||
* @return size of the record in bytes
|
||||
*/
|
||||
size_t
|
||||
get_size () const
|
||||
{
|
||||
return get_field (_length_field_pos, _length_field_width) * RCS_DYN_STORAGE_LENGTH_UNIT;
|
||||
} /* get_size */
|
||||
|
||||
rcs_record_t *get_prev () const;
|
||||
|
||||
ecma_length_t get_charset (ecma_char_t *buff, size_t size);
|
||||
|
||||
int compare_zt (const ecma_char_t *, size_t);
|
||||
bool equal (lit_charset_record_t *);
|
||||
bool equal_zt (const ecma_char_t *);
|
||||
bool equal_non_zt (const ecma_char_t *, ecma_length_t);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Set record's size (the value of the 'length' field in the header)
|
||||
*/
|
||||
void
|
||||
set_size (size_t size) /**< size in bytes */
|
||||
{
|
||||
JERRY_ASSERT (JERRY_ALIGNUP (size, RCS_DYN_STORAGE_ALIGNMENT) == size);
|
||||
|
||||
set_field (_length_field_pos, _length_field_width, size >> RCS_DYN_STORAGE_ALIGNMENT_LOG);
|
||||
} /* set_size */
|
||||
|
||||
/**
|
||||
* Set record's hash (the value of the 'hash' field in the header)
|
||||
*/
|
||||
void
|
||||
set_hash (ecma_string_hash_t hash) /**< hash value */
|
||||
{
|
||||
set_field (_hash_field_pos, _hash_field_width, hash);
|
||||
} /* set_hash */
|
||||
|
||||
void set_prev (rcs_record_t *);
|
||||
|
||||
void set_charset (const ecma_char_t *, size_t);
|
||||
|
||||
/**
|
||||
* Offset and length of 'alignment' field, in bits
|
||||
*/
|
||||
static const uint32_t _alignment_field_pos = _fields_offset_begin;
|
||||
static const uint32_t _alignment_field_width = 2u;
|
||||
|
||||
/**
|
||||
* Offset and length of 'hash' field, in bits
|
||||
*/
|
||||
static const uint32_t _hash_field_pos = _alignment_field_pos + _alignment_field_width + 2u;
|
||||
static const uint32_t _hash_field_width = 8u;
|
||||
|
||||
/**
|
||||
* Offset and length of 'alignment' field, in bits
|
||||
*/
|
||||
static const uint32_t _length_field_pos = _hash_field_pos + _hash_field_width;
|
||||
static const uint32_t _length_field_width = 16u;
|
||||
|
||||
/**
|
||||
* Offset and length of 'prev' field, in bits
|
||||
*/
|
||||
static const uint32_t _prev_field_pos = _length_field_pos + _length_field_width;
|
||||
static const uint32_t _prev_field_width = rcs_cpointer_t::bit_field_width;
|
||||
|
||||
static const size_t _header_size = RCS_DYN_STORAGE_LENGTH_UNIT + RCS_DYN_STORAGE_LENGTH_UNIT / 2;
|
||||
}; /* lit_charset_record_t */
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* --------------------------------------
|
||||
*/
|
||||
class lit_magic_record_t : public rcs_record_t
|
||||
{
|
||||
friend class rcs_recordset_t;
|
||||
friend class lit_literal_storage_t;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Calculate the size that record will occupy inside the storage
|
||||
*
|
||||
* @return size of the record in bytes
|
||||
*/
|
||||
static size_t size ()
|
||||
{
|
||||
return _size;
|
||||
} /* size */
|
||||
|
||||
/**
|
||||
* Get the size of the header part of the record
|
||||
*
|
||||
* @return size of the header in bytes
|
||||
*/
|
||||
static size_t header_size ()
|
||||
{
|
||||
return _size;
|
||||
} /* header_size */
|
||||
|
||||
/**
|
||||
* Get the size of the record
|
||||
*
|
||||
* @return size of the record in bytes
|
||||
*/
|
||||
size_t get_size () const
|
||||
{
|
||||
return _size;
|
||||
} /* get_size */
|
||||
|
||||
/**
|
||||
* Get magic string id which is held by the record
|
||||
*
|
||||
* @return magic string id
|
||||
*/
|
||||
ecma_magic_string_id_t get_magic_str_id () const
|
||||
{
|
||||
uint32_t id = get_field (magic_field_pos, magic_field_width);
|
||||
JERRY_ASSERT (id < ECMA_MAGIC_STRING__COUNT);
|
||||
return (ecma_magic_string_id_t) id;
|
||||
} /* get_magic_str_id */
|
||||
|
||||
private:
|
||||
/**
|
||||
* Set record's size (the value of the 'length' field in the header)
|
||||
*/
|
||||
void set_size (size_t size) /**< size in bytes */
|
||||
{
|
||||
JERRY_ASSERT (size == get_size ());
|
||||
} /* set_size */
|
||||
|
||||
void set_magic_str_id (ecma_magic_string_id_t id)
|
||||
{
|
||||
set_field (magic_field_pos, magic_field_width, id);
|
||||
} /* set_magic_str_id */
|
||||
|
||||
/**
|
||||
* Get previous record in the literal storage
|
||||
*
|
||||
* @return pointer to the previous record relative to this record, or NULL if this is the first record in the
|
||||
* storage
|
||||
*/
|
||||
rcs_record_t *get_prev () const
|
||||
{
|
||||
return get_pointer (prev_field_pos, prev_field_width);
|
||||
} /* get_prev */
|
||||
|
||||
/**
|
||||
* Set the pointer to the previous record inside the literal storage (sets 'prev' field in the header)
|
||||
*/
|
||||
void set_prev (rcs_record_t *prev_rec_p)
|
||||
{
|
||||
set_pointer (prev_field_pos, prev_field_width, prev_rec_p);
|
||||
} /* set_prev */
|
||||
|
||||
|
||||
/**
|
||||
* Offset and length of 'magic string id' field, in bits
|
||||
*/
|
||||
static const uint32_t magic_field_pos = _fields_offset_begin;
|
||||
static const uint32_t magic_field_width = 12u;
|
||||
|
||||
/**
|
||||
* Offset and length of 'prev' field, in bits
|
||||
*/
|
||||
static const uint32_t prev_field_pos = magic_field_pos + magic_field_width;
|
||||
static const uint32_t prev_field_width = rcs_cpointer_t::bit_field_width;
|
||||
|
||||
static const size_t _size = RCS_DYN_STORAGE_LENGTH_UNIT;
|
||||
}; /* lit_magic_record_t */
|
||||
|
||||
|
||||
/**
|
||||
* Number record
|
||||
* Doesn't hold any characters, holds a number. Numbers from source code are represented as number literals.
|
||||
*
|
||||
* Layout:
|
||||
* ------- header -----------------------
|
||||
* type (4 bits)
|
||||
* magic string id (12 bits)
|
||||
* pointer to prev (16 bits)
|
||||
* --------------------------------------
|
||||
*/
|
||||
class lit_number_record_t : public rcs_record_t
|
||||
{
|
||||
friend class rcs_recordset_t;
|
||||
friend class lit_literal_storage_t;
|
||||
|
||||
public:
|
||||
|
||||
static size_t
|
||||
size ()
|
||||
{
|
||||
return _size;
|
||||
} /* size */
|
||||
|
||||
/**
|
||||
* Get the size of the header part of the record
|
||||
*
|
||||
* @return size of the header in bytes
|
||||
*/
|
||||
static size_t
|
||||
header_size ()
|
||||
{
|
||||
return _header_size;
|
||||
} /* header_size */
|
||||
|
||||
/**
|
||||
* Get the size of the record
|
||||
*
|
||||
* @return size of the record in bytes
|
||||
*/
|
||||
size_t
|
||||
get_size () const
|
||||
{
|
||||
return _size;
|
||||
} /* get_size */
|
||||
|
||||
/**
|
||||
* Get previous record in the literal storage
|
||||
*
|
||||
* @return pointer to the previous record relative to this record, or NULL if this is the first record in the
|
||||
* storage
|
||||
*/
|
||||
rcs_record_t *
|
||||
get_prev () const
|
||||
{
|
||||
return get_pointer (prev_field_pos, prev_field_width);
|
||||
} /* get_prev */
|
||||
|
||||
/**
|
||||
* Set the pointer to the previous record inside the literal storage (sets 'prev' field in the header)
|
||||
*/
|
||||
void
|
||||
set_prev (rcs_record_t *prev_rec_p)
|
||||
{
|
||||
set_pointer (prev_field_pos, prev_field_width, prev_rec_p);
|
||||
} /* set_prev */
|
||||
|
||||
/**
|
||||
* Get the number which is held by the record
|
||||
*
|
||||
* @return number
|
||||
*/
|
||||
ecma_number_t
|
||||
get_number () const
|
||||
{
|
||||
rcs_record_iterator_t it ((rcs_recordset_t *)&lit_storage,
|
||||
(rcs_record_t *)this);
|
||||
it.skip (header_size ());
|
||||
|
||||
return it.read<ecma_number_t> ();
|
||||
} /* get_number */
|
||||
|
||||
private:
|
||||
/**
|
||||
* Set record's size (the value of the 'length' field in the header)
|
||||
*/
|
||||
void
|
||||
set_size (size_t size) /**< size in bytes */
|
||||
{
|
||||
JERRY_ASSERT (size == get_size ());
|
||||
} /* set_size */
|
||||
|
||||
/**
|
||||
* Offset and length of 'prev' field, in bits
|
||||
*/
|
||||
static const uint32_t prev_field_pos = _fields_offset_begin + 12u;
|
||||
static const uint32_t prev_field_width = rcs_cpointer_t::bit_field_width;
|
||||
|
||||
static const size_t _header_size = RCS_DYN_STORAGE_LENGTH_UNIT;
|
||||
static const size_t _size = _header_size + sizeof (ecma_number_t);
|
||||
}; /* lit_number_record_t */
|
||||
|
||||
/**
|
||||
* Literal storage
|
||||
*
|
||||
* Represents flexible storage for the literals. The following records could be created inside the storage:
|
||||
* - charset literal (lit_charset_record_t)
|
||||
* - magic string literal (lit_magic_record_t)
|
||||
* - number literal (lit_number_record_t)
|
||||
*/
|
||||
class lit_literal_storage_t : public rcs_recordset_t
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
LIT_STR = _first_type_id,
|
||||
LIT_MAGIC_STR,
|
||||
LIT_NUMBER
|
||||
};
|
||||
|
||||
lit_charset_record_t *create_charset_record (const ecma_char_t *, size_t);
|
||||
lit_magic_record_t *create_magic_record (ecma_magic_string_id_t);
|
||||
lit_number_record_t *create_number_record (ecma_number_t);
|
||||
|
||||
void dump ();
|
||||
|
||||
private:
|
||||
virtual rcs_record_t *get_prev (rcs_record_t *);
|
||||
virtual void set_prev (rcs_record_t *, rcs_record_t *);
|
||||
virtual size_t get_record_size (rcs_record_t *);
|
||||
}; /* lit_literal_storage_t */
|
||||
|
||||
#define LIT_STR_T (lit_literal_storage_t::LIT_STR)
|
||||
#define LIT_MAGIC_STR_T (lit_literal_storage_t::LIT_MAGIC_STR)
|
||||
#define LIT_NUMBER_T (lit_literal_storage_t::LIT_NUMBER)
|
||||
|
||||
#endif /* LIT_LITERAL_STORAGE_H */
|
||||
@@ -0,0 +1,504 @@
|
||||
/* 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 "lit-literal.h"
|
||||
#include "ecma-helpers.h"
|
||||
|
||||
/**
|
||||
* Initialize literal storage
|
||||
*/
|
||||
void
|
||||
lit_init ()
|
||||
{
|
||||
new (&lit_storage) lit_literal_storage_t ();
|
||||
lit_storage.init ();
|
||||
} /* lit_init */
|
||||
|
||||
/**
|
||||
* Finalize literal storage
|
||||
*/
|
||||
void
|
||||
lit_finalize ()
|
||||
{
|
||||
lit_storage.cleanup ();
|
||||
lit_storage.finalize ();
|
||||
} /* lit_finalize */
|
||||
|
||||
/**
|
||||
* Dump records from the literal storage
|
||||
*/
|
||||
void
|
||||
lit_dump_literals ()
|
||||
{
|
||||
lit_storage.dump ();
|
||||
} /* lit_dump_literals */
|
||||
|
||||
/**
|
||||
* Create new literal in literal storage from characters buffer.
|
||||
* Don't check if the same literal already exists.
|
||||
*
|
||||
* @return pointer to created record
|
||||
*/
|
||||
literal_t
|
||||
lit_create_literal_from_charset (const ecma_char_t *str, /**< string to initialize the record,
|
||||
* could be non-zero-terminated */
|
||||
ecma_length_t len) /**< length of the string */
|
||||
{
|
||||
JERRY_ASSERT (str || !len);
|
||||
for (ecma_magic_string_id_t msi = (ecma_magic_string_id_t) 0;
|
||||
msi < ECMA_MAGIC_STRING__COUNT;
|
||||
msi = (ecma_magic_string_id_t) (msi + 1))
|
||||
{
|
||||
if (ecma_zt_string_length (ecma_get_magic_string_zt (msi)) != len)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp ((const char *) str, (const char *) ecma_get_magic_string_zt (msi), len))
|
||||
{
|
||||
return lit_storage.create_magic_record (msi);
|
||||
}
|
||||
}
|
||||
|
||||
return lit_storage.create_charset_record (str, len * sizeof (ecma_char_t));
|
||||
} /* lit_create_literal_from_charset */
|
||||
|
||||
/**
|
||||
* Find a literal in literal storage.
|
||||
* Only charset and magic string records are checked during search.
|
||||
*
|
||||
* @return pointer to a literal or NULL if no corresponding literal exists
|
||||
*/
|
||||
literal_t
|
||||
lit_find_literal_by_charset (const ecma_char_t *str, /**< a string to search for */
|
||||
ecma_length_t len) /**< length of the string */
|
||||
{
|
||||
JERRY_ASSERT (str || !len);
|
||||
for (literal_t lit = lit_storage.get_first (); lit != NULL; lit = lit_storage.get_next (lit))
|
||||
{
|
||||
rcs_record_t::type_t type = lit->get_type ();
|
||||
|
||||
if (type == LIT_STR_T)
|
||||
{
|
||||
if (static_cast<lit_charset_record_t *>(lit)->get_length () != len)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!static_cast<lit_charset_record_t *>(lit)->compare_zt (str, len))
|
||||
{
|
||||
return lit;
|
||||
}
|
||||
}
|
||||
else if (type == LIT_MAGIC_STR_T)
|
||||
{
|
||||
ecma_magic_string_id_t magic_id = static_cast<lit_magic_record_t *>(lit)->get_magic_str_id ();
|
||||
const char *magic_str = (const char *)ecma_get_magic_string_zt (magic_id);
|
||||
|
||||
if (strlen (magic_str) != len)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strncmp (magic_str, (const char *) str, strlen (magic_str)))
|
||||
{
|
||||
return lit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} /* lit_find_literal_by_charset */
|
||||
|
||||
/**
|
||||
* Check if a literal which holds the passed string exists.
|
||||
* If it doesn't exist, create a new one.
|
||||
*
|
||||
* @return pointer to existing or newly created record
|
||||
*/
|
||||
literal_t
|
||||
lit_find_or_create_literal_from_charset (const ecma_char_t *str, /**< string, could be non-zero-terminated */
|
||||
ecma_length_t len) /**< length of the string */
|
||||
{
|
||||
literal_t lit = lit_find_literal_by_charset (str, len);
|
||||
|
||||
if (lit == NULL)
|
||||
{
|
||||
lit = lit_create_literal_from_charset (str, len);
|
||||
}
|
||||
|
||||
return lit;
|
||||
} /* lit_find_or_create_literal_from_s */
|
||||
|
||||
|
||||
/**
|
||||
* Create new literal in literal storage from number.
|
||||
*
|
||||
* @return pointer to a newly created record
|
||||
*/
|
||||
literal_t
|
||||
lit_create_literal_from_num (ecma_number_t num) /**< number to initialize a new number literal */
|
||||
{
|
||||
return lit_storage.create_number_record (num);
|
||||
} /* lit_create_literal_from_num */
|
||||
|
||||
/**
|
||||
* Find existing or create new number literal in literal storage.
|
||||
*
|
||||
* @return pointer to existing or a newly created record
|
||||
*/
|
||||
literal_t
|
||||
lit_find_or_create_literal_from_num (ecma_number_t num) /**< number which a literal should contain */
|
||||
{
|
||||
literal_t lit = lit_find_literal_by_num (num);
|
||||
|
||||
if (lit == NULL)
|
||||
{
|
||||
lit = lit_create_literal_from_num (num);
|
||||
}
|
||||
|
||||
return lit;
|
||||
} /* lit_find_or_create_literal_from_num */
|
||||
|
||||
/**
|
||||
* Find an existing number literal which contains the passed number
|
||||
*
|
||||
* @return pointer to existing or null
|
||||
*/
|
||||
literal_t
|
||||
lit_find_literal_by_num (ecma_number_t num) /**< a number to search for */
|
||||
{
|
||||
for (literal_t lit = lit_storage.get_first (); lit != NULL; lit = lit_storage.get_next (lit))
|
||||
{
|
||||
rcs_record_t::type_t type = lit->get_type ();
|
||||
|
||||
if (type != LIT_NUMBER_T)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ecma_number_t lit_num = static_cast<lit_number_record_t *>(lit)->get_number ();
|
||||
|
||||
if (lit_num == num)
|
||||
{
|
||||
return lit;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
} /* lit_find_literal_by_num */
|
||||
|
||||
/**
|
||||
* Check if literal equals to charset record
|
||||
*
|
||||
* @return true if equal
|
||||
* false otherwise
|
||||
*/
|
||||
static bool
|
||||
lit_literal_equal_charset_rec (literal_t lit, /**< literal to compare */
|
||||
lit_charset_record_t *record) /**< charset record to compare */
|
||||
{
|
||||
switch (lit->get_type ())
|
||||
{
|
||||
case LIT_STR_T:
|
||||
{
|
||||
return static_cast<lit_charset_record_t *>(lit)->equal (record);
|
||||
}
|
||||
case LIT_MAGIC_STR_T:
|
||||
{
|
||||
return record->equal_zt (ecma_get_magic_string_zt (static_cast<lit_magic_record_t *>(lit)->get_magic_str_id ()));
|
||||
}
|
||||
case LIT_NUMBER_T:
|
||||
{
|
||||
ecma_char_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
|
||||
ecma_number_to_zt_string (static_cast<lit_number_record_t *>(lit)->get_number (),
|
||||
buff,
|
||||
ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER);
|
||||
|
||||
return record->equal_zt (buff);
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
}
|
||||
}
|
||||
} /* lit_literal_equal_charset_rec */
|
||||
|
||||
/**
|
||||
* Check if literal equals to zero-terminated string
|
||||
*
|
||||
* @return true if equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
lit_literal_equal_zt (literal_t lit, /**< literal to compare */
|
||||
const ecma_char_t *str) /**< zero-terminated string to compare */
|
||||
{
|
||||
switch (lit->get_type ())
|
||||
{
|
||||
case LIT_STR_T:
|
||||
{
|
||||
return static_cast<lit_charset_record_t *>(lit)->equal_zt (str);
|
||||
}
|
||||
case LIT_MAGIC_STR_T:
|
||||
{
|
||||
ecma_magic_string_id_t magic_id = static_cast<lit_magic_record_t *>(lit)->get_magic_str_id ();
|
||||
|
||||
return ecma_compare_zt_strings (str, ecma_get_magic_string_zt (magic_id));
|
||||
}
|
||||
case LIT_NUMBER_T:
|
||||
{
|
||||
ecma_char_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
|
||||
ecma_number_to_zt_string (static_cast<lit_number_record_t *>(lit)->get_number (),
|
||||
buff,
|
||||
ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER);
|
||||
|
||||
return ecma_compare_zt_strings (str, buff);
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
}
|
||||
}
|
||||
} /* lit_literal_equal_zt */
|
||||
|
||||
/**
|
||||
* Check if literal contains the string equal to the passed number
|
||||
*
|
||||
* @return true if equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
lit_literal_equal_num (literal_t lit, /**< literal to check */
|
||||
ecma_number_t num) /**< number to compare with */
|
||||
{
|
||||
ecma_char_t buff[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
|
||||
ecma_number_to_zt_string (num, buff, ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER);
|
||||
|
||||
return lit_literal_equal_zt (lit, buff);
|
||||
} /* lit_literal_equal_num */
|
||||
|
||||
/**
|
||||
* Check if two literals are equal
|
||||
*
|
||||
* @return true if equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
lit_literal_equal (literal_t lit1, /**< first literal */
|
||||
literal_t lit2) /**< second literal */
|
||||
{
|
||||
switch (lit2->get_type ())
|
||||
{
|
||||
case lit_literal_storage_t::LIT_STR:
|
||||
{
|
||||
return lit_literal_equal_charset_rec (lit1, static_cast<lit_charset_record_t *>(lit2));
|
||||
}
|
||||
case lit_literal_storage_t::LIT_MAGIC_STR:
|
||||
{
|
||||
ecma_magic_string_id_t magic_id = static_cast<lit_magic_record_t *>(lit2)->get_magic_str_id ();
|
||||
|
||||
return lit_literal_equal_zt (lit1, ecma_get_magic_string_zt (magic_id));
|
||||
}
|
||||
case lit_literal_storage_t::LIT_NUMBER:
|
||||
{
|
||||
return lit_literal_equal_num (lit1, static_cast<lit_number_record_t *>(lit2)->get_number ());
|
||||
}
|
||||
default:
|
||||
{
|
||||
JERRY_UNREACHABLE ();
|
||||
}
|
||||
}
|
||||
} /* lit_literal_equal */
|
||||
|
||||
/**
|
||||
* Check if literal equals to zero-terminated string.
|
||||
* Check that literal is a string literal before performing detailed comparison.
|
||||
*
|
||||
* @return true if equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
lit_literal_equal_type_zt (literal_t lit, /**< literal to compare */
|
||||
const ecma_char_t *str) /**< zero-terminated string */
|
||||
{
|
||||
if (lit->get_type () != LIT_STR_T
|
||||
&& lit->get_type () != LIT_MAGIC_STR_T)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return lit_literal_equal_zt (lit, str);
|
||||
} /* lit_literal_equal_type_zt */
|
||||
|
||||
/**
|
||||
* Check if literal contains the string equal to the passed number.
|
||||
* Check that literal is a number literal before performing detailed comparison.
|
||||
*
|
||||
* @return true if equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
lit_literal_equal_type_num (literal_t lit, /**< literal to check */
|
||||
ecma_number_t num) /**< number to compare with */
|
||||
{
|
||||
if (lit->get_type () != lit_literal_storage_t::LIT_NUMBER)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return lit_literal_equal_num (lit, num);
|
||||
} /* lit_literal_equal_type_num */
|
||||
|
||||
/**
|
||||
* Check if two literals are equal
|
||||
* Compare types of literals before performing detailed comparison.
|
||||
*
|
||||
* @return true if equal
|
||||
* false otherwise
|
||||
*/
|
||||
bool
|
||||
lit_literal_equal_type (literal_t lit1, /**< first literal */
|
||||
literal_t lit2) /**< second literal */
|
||||
{
|
||||
if (lit1->get_type () != lit2->get_type ())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return lit_literal_equal (lit1, lit2);
|
||||
} /* lit_literal_equal_type */
|
||||
|
||||
|
||||
/**
|
||||
* Get the contents of the literal as a zero-terminated string.
|
||||
* If literal is a magic string record, the corresponding string is not copied to the buffer,
|
||||
* but is returned directly.
|
||||
*
|
||||
* @return pointer to the zero-terminated string.
|
||||
*/
|
||||
const ecma_char_t *
|
||||
lit_literal_to_charset (literal_t lit, /**< literal to be processed */
|
||||
ecma_char_t *buff, /**< buffer to use as a string storage */
|
||||
size_t size) /**< size of the buffer */
|
||||
{
|
||||
JERRY_ASSERT (buff != NULL && size > sizeof (ecma_char_t));
|
||||
rcs_record_t::type_t type = lit->get_type ();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case LIT_STR_T:
|
||||
{
|
||||
lit_charset_record_t *ch_rec_p = static_cast<lit_charset_record_t *> (lit);
|
||||
ecma_length_t index = ch_rec_p->get_charset (buff, size);
|
||||
|
||||
if (index != 0 && ((size_t)index + 1) * sizeof (ecma_char_t) > size)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
buff[index] = '\0';
|
||||
|
||||
return buff;
|
||||
}
|
||||
case LIT_MAGIC_STR_T:
|
||||
{
|
||||
return ecma_get_magic_string_zt (static_cast<lit_magic_record_t *> (lit)->get_magic_str_id ());
|
||||
}
|
||||
case LIT_NUMBER_T:
|
||||
{
|
||||
ecma_number_to_zt_string (static_cast<lit_number_record_t *> (lit)->get_number (), buff, (ssize_t)size);
|
||||
|
||||
return buff;
|
||||
}
|
||||
default: JERRY_UNREACHABLE ();
|
||||
}
|
||||
|
||||
JERRY_UNREACHABLE ();
|
||||
} /* lit_literal_to_charset */
|
||||
|
||||
/**
|
||||
* Get the contents of the literal as a C string.
|
||||
* If literal holds a very long string, it would be trimmed to ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER characters.
|
||||
*
|
||||
* @return pointer to the C string.
|
||||
*/
|
||||
const char *
|
||||
lit_literal_to_str_internal_buf (literal_t lit) /**< literal */
|
||||
{
|
||||
const ecma_length_t buff_size = ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER;
|
||||
static ecma_char_t buff[buff_size];
|
||||
|
||||
return (const char *)lit_literal_to_charset (lit, buff, buff_size);
|
||||
} /* lit_literal_to_str_internal_buf */
|
||||
|
||||
|
||||
/**
|
||||
* Check if literal really exists in the storage
|
||||
*
|
||||
* @return true if literal exists in the storage
|
||||
* false otherwise
|
||||
*/
|
||||
static bool
|
||||
lit_literal_exists (literal_t lit) /**< literal to check for existence */
|
||||
{
|
||||
for (literal_t l = lit_storage.get_first (); l != NULL; l = lit_storage.get_next (l))
|
||||
{
|
||||
if (l == lit)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} /* lit_literal_exists */
|
||||
|
||||
/**
|
||||
* Convert compressed pointer to literal
|
||||
*
|
||||
* @return literal
|
||||
*/
|
||||
literal_t
|
||||
lit_get_literal_by_cp (lit_cpointer_t lit_cp) /**< compressed pointer to literal */
|
||||
{
|
||||
JERRY_ASSERT (lit_cp.packed_value != MEM_CP_NULL);
|
||||
literal_t lit = lit_cpointer_t::decompress (lit_cp);
|
||||
JERRY_ASSERT (lit_literal_exists (lit));
|
||||
|
||||
return lit;
|
||||
} /* lit_get_literal_by_cp */
|
||||
|
||||
ecma_string_hash_t
|
||||
lit_charset_literal_get_hash (literal_t lit) /**< literal */
|
||||
{
|
||||
return static_cast<lit_charset_record_t *> (lit)->get_hash ();
|
||||
} /* lit_charset_literal_get_hash */
|
||||
|
||||
ecma_magic_string_id_t
|
||||
lit_magic_record_get_magic_str_id (literal_t lit) /**< literal */
|
||||
{
|
||||
return static_cast<lit_magic_record_t *> (lit)->get_magic_str_id ();
|
||||
} /* lit_magic_record_get_magic_str_id */
|
||||
|
||||
int32_t
|
||||
lit_charset_record_get_length (literal_t lit) /**< literal */
|
||||
{
|
||||
return static_cast<lit_charset_record_t *> (lit)->get_length ();;
|
||||
} /* lit_charset_record_get_length */
|
||||
|
||||
ecma_number_t
|
||||
lit_charset_literal_get_number (literal_t lit) /**< literal */
|
||||
{
|
||||
return static_cast<lit_number_record_t *> (lit)->get_number ();;
|
||||
} /* lit_charset_literal_get_number */
|
||||
@@ -0,0 +1,55 @@
|
||||
/* 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 LIT_LITERAL_H
|
||||
#define LIT_LITERAL_H
|
||||
|
||||
#include "ecma-globals.h"
|
||||
#include "lit-literal-storage.h"
|
||||
|
||||
#define LITERAL_TO_REWRITE (INVALID_VALUE - 1)
|
||||
|
||||
void lit_init ();
|
||||
void lit_finalize ();
|
||||
void lit_dump_literals ();
|
||||
|
||||
literal_t lit_create_literal_from_charset (const ecma_char_t *, ecma_length_t);
|
||||
literal_t lit_find_literal_by_charset (const ecma_char_t *, ecma_length_t);
|
||||
literal_t lit_find_or_create_literal_from_charset (const ecma_char_t *, ecma_length_t);
|
||||
|
||||
literal_t lit_create_literal_from_num (ecma_number_t);
|
||||
literal_t lit_find_literal_by_num (ecma_number_t);
|
||||
literal_t lit_find_or_create_literal_from_num (ecma_number_t);
|
||||
|
||||
bool lit_literal_equal_zt (literal_t, const ecma_char_t *);
|
||||
bool lit_literal_equal_num (literal_t, ecma_number_t);
|
||||
bool lit_literal_equal (literal_t, literal_t);
|
||||
|
||||
bool lit_literal_equal_type_zt (literal_t, const ecma_char_t *);
|
||||
bool lit_literal_equal_type_num (literal_t, ecma_number_t);
|
||||
bool lit_literal_equal_type (literal_t, literal_t);
|
||||
|
||||
const ecma_char_t *lit_literal_to_charset (literal_t, ecma_char_t *, size_t);
|
||||
const char *lit_literal_to_str_internal_buf (literal_t);
|
||||
|
||||
literal_t lit_get_literal_by_cp (lit_cpointer_t);
|
||||
|
||||
ecma_string_hash_t lit_charset_literal_get_hash (literal_t);
|
||||
ecma_number_t lit_charset_literal_get_number (literal_t);
|
||||
int32_t lit_charset_record_get_length (literal_t);
|
||||
|
||||
ecma_magic_string_id_t lit_magic_record_get_magic_str_id (literal_t);
|
||||
|
||||
#endif /* LIT_LITERAL_H */
|
||||
@@ -35,6 +35,15 @@ rcs_chunked_list_t::free (void)
|
||||
JERRY_ASSERT (tail_p == NULL);
|
||||
} /* rcs_chunked_list_t::free */
|
||||
|
||||
void
|
||||
rcs_chunked_list_t::cleanup (void)
|
||||
{
|
||||
while (head_p)
|
||||
{
|
||||
remove (head_p);
|
||||
}
|
||||
} /* rcs_chunked_list_t::cleanup */
|
||||
|
||||
/**
|
||||
* Get first node of the list
|
||||
*
|
||||
|
||||
@@ -55,6 +55,7 @@ public:
|
||||
} node_t;
|
||||
|
||||
void init (void);
|
||||
void cleanup (void);
|
||||
void free (void);
|
||||
|
||||
node_t *get_first (void) const;
|
||||
|
||||
@@ -74,6 +74,12 @@ public:
|
||||
_chunk_list.free ();
|
||||
} /* finalize */
|
||||
|
||||
/* Free memory occupied by the dynamic storage */
|
||||
void cleanup (void)
|
||||
{
|
||||
_chunk_list.cleanup ();
|
||||
} /* cleanup */
|
||||
|
||||
/**
|
||||
* Record type
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
/* 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 "ecma-helpers.h"
|
||||
#include "lit-literal.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern void srand (unsigned int __seed);
|
||||
extern int rand (void);
|
||||
extern long int time (long int *__timer);
|
||||
extern int printf (__const char *__restrict __format, ...);
|
||||
extern void *memset (void *__s, int __c, size_t __n);
|
||||
}
|
||||
|
||||
// Heap size is 32K
|
||||
#define test_heap_size (32 * 1024)
|
||||
|
||||
// Iterations count
|
||||
#define test_iters 64
|
||||
|
||||
// Subiterations count
|
||||
#define test_sub_iters 64
|
||||
|
||||
// Max characters in a string
|
||||
#define max_characters_in_string 256
|
||||
|
||||
static void
|
||||
generate_string (ecma_char_t *str, ecma_length_t len)
|
||||
{
|
||||
static const ecma_char_t characters[] = "!@#$%^&*()_+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
|
||||
static const ecma_length_t length = (ecma_length_t) (sizeof (characters) / sizeof (ecma_char_t) - 1);
|
||||
for (ecma_length_t i = 0; i < len; ++i)
|
||||
{
|
||||
str[i] = characters[(unsigned long) rand () % length];
|
||||
}
|
||||
}
|
||||
|
||||
static ecma_number_t
|
||||
generate_number ()
|
||||
{
|
||||
ecma_number_t num = ((ecma_number_t) rand () / 32767.0);
|
||||
if (rand () % 2)
|
||||
{
|
||||
num = -num;
|
||||
}
|
||||
int power = rand () % 30;
|
||||
while (power-- > 0)
|
||||
{
|
||||
num *= 10;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
int
|
||||
main (int __attr_unused___ argc,
|
||||
char __attr_unused___ **argv)
|
||||
{
|
||||
const ecma_char_t *ptrs[test_sub_iters];
|
||||
ecma_number_t numbers[test_sub_iters];
|
||||
ecma_char_t strings[test_sub_iters][max_characters_in_string + 1];
|
||||
ecma_length_t lengths[test_sub_iters];
|
||||
|
||||
mem_init ();
|
||||
lit_init ();
|
||||
|
||||
srand ((unsigned int) time (NULL));
|
||||
int k = rand ();
|
||||
printf ("seed=%d\n", k);
|
||||
srand ((unsigned int) k);
|
||||
|
||||
for (uint32_t i = 0; i < test_iters; i++)
|
||||
{
|
||||
memset (numbers, 0, sizeof (ecma_number_t) * test_sub_iters);
|
||||
memset (lengths, 0, sizeof (ecma_length_t) * test_sub_iters);
|
||||
memset (ptrs, 0, sizeof (ecma_char_t *) * test_sub_iters);
|
||||
|
||||
for (uint32_t j = 0; j < test_sub_iters; j++)
|
||||
{
|
||||
int type = rand () % 3;
|
||||
if (type == 0)
|
||||
{
|
||||
lengths[j] = (ecma_length_t) (rand () % max_characters_in_string + 1);
|
||||
generate_string (strings[j], lengths[j]);
|
||||
lit_create_literal_from_charset (strings[j], lengths[j]);
|
||||
strings[j][lengths[j]] = '\0';
|
||||
ptrs[j] = strings[j];
|
||||
JERRY_ASSERT (ptrs[j]);
|
||||
}
|
||||
else if (type == 1)
|
||||
{
|
||||
ecma_magic_string_id_t msi = (ecma_magic_string_id_t) (rand () % ECMA_MAGIC_STRING__COUNT);
|
||||
ptrs[j] = ecma_get_magic_string_zt (msi);
|
||||
JERRY_ASSERT (ptrs[j]);
|
||||
lengths[j] = (ecma_length_t) ecma_zt_string_length (ptrs[j]);
|
||||
lit_create_literal_from_charset (ptrs[j], lengths[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
ecma_number_t num = generate_number ();
|
||||
lengths[j] = ecma_number_to_zt_string (num, strings[j], max_characters_in_string);
|
||||
lit_create_literal_from_num (num);
|
||||
}
|
||||
}
|
||||
|
||||
// Add empty string
|
||||
lit_create_literal_from_charset (NULL, 0);
|
||||
|
||||
for (uint32_t j = 0; j < test_sub_iters; j++)
|
||||
{
|
||||
literal_t lit1;
|
||||
literal_t lit2;
|
||||
if (ptrs[j])
|
||||
{
|
||||
lit1 = lit_find_or_create_literal_from_charset (ptrs[j], lengths[j]);
|
||||
lit2 = lit_find_literal_by_charset (ptrs[j], lengths[j]);
|
||||
JERRY_ASSERT (lit_literal_equal_zt (lit1, ptrs[j]));
|
||||
JERRY_ASSERT (lit_literal_equal_type_zt (lit2, ptrs[j]));
|
||||
}
|
||||
else
|
||||
{
|
||||
lit1 = lit_find_or_create_literal_from_num (numbers[j]);
|
||||
lit2 = lit_find_literal_by_num (numbers[j]);
|
||||
JERRY_ASSERT (lit_literal_equal_num (lit1, numbers[j]));
|
||||
JERRY_ASSERT (lit_literal_equal_type_num (lit2, numbers[j]));
|
||||
}
|
||||
JERRY_ASSERT (lit1);
|
||||
JERRY_ASSERT (lit2);
|
||||
JERRY_ASSERT (lit1 == lit2);
|
||||
JERRY_ASSERT (lit_literal_equal (lit1, lit2));
|
||||
}
|
||||
|
||||
// Check empty string exists
|
||||
JERRY_ASSERT (lit_find_literal_by_charset (NULL, 0));
|
||||
|
||||
lit_storage.cleanup ();
|
||||
JERRY_ASSERT (lit_storage.get_first () == NULL);
|
||||
}
|
||||
|
||||
lit_finalize ();
|
||||
mem_finalize (true);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user