Compact Byte Code parser and executor for Jerry.

JerryScript-DCO-1.0-Signed-off-by: László Langó llango.u-szeged@partner.samsung.com
JerryScript-DCO-1.0-Signed-off-by: Tamas Gergely tgergely.u-szeged@partner.samsung.com
JerryScript-DCO-1.0-Signed-off-by: Zsolt Borbély zsborbely.u-szeged@partner.samsung.com
JerryScript-DCO-1.0-Signed-off-by: Roland Takacs rtakacs.u-szeged@partner.samsung.com
JerryScript-DCO-1.0-Signed-off-by: István Kádár ikadar@inf.u-szeged.hu
JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2016-02-05 00:10:10 -08:00
parent db6caf3c48
commit 4d2dd22ced
92 changed files with 17184 additions and 20276 deletions
-834
View File
@@ -1,834 +0,0 @@
/* 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 "bytecode-data.h"
#include "pretty-printer.h"
#include "opcodes-dumper.h"
/**
* First node of the list of bytecodes
*/
static bytecode_data_header_t *first_bytecode_header_p = NULL;
/**
* Bytecode header in snapshot
*/
typedef struct
{
uint32_t size; /**< size of this bytecode data record */
uint32_t instrs_size; /**< size of instructions array */
uint32_t idx_to_lit_map_size; /**< size of idx-to-lit map */
uint32_t func_scopes_count; /**< count of function scopes inside current scope */
uint32_t var_decls_count; /**< count of variable declarations insdie current scope */
uint8_t is_strict : 1; /**< code is strict mode code */
uint8_t is_ref_arguments_identifier : 1; /**< code doesn't reference 'arguments' identifier */
uint8_t is_ref_eval_identifier : 1; /**< code doesn't reference 'eval' identifier */
uint8_t is_args_moved_to_regs : 1; /**< the function's arguments are moved to registers,
* so should be initialized in vm registers,
* and not in lexical environment */
uint8_t is_no_lex_env : 1; /**< no lex. env. is necessary for the scope */
} jerry_snapshot_bytecode_header_t;
/**
* Fill the fields of bytecode data header with specified values
*/
static void
bc_fill_bytecode_data_header (bytecode_data_header_t *bc_header_p, /**< byte-code scope data header to fill */
lit_id_hash_table *lit_id_hash_table_p, /**< (idx, block id) -> literal hash table */
vm_instr_t *bytecode_p, /**< byte-code instructions array */
mem_cpointer_t *declarations_p, /**< array of function / variable declarations */
uint16_t func_scopes_count, /**< number of function declarations / expressions
* located immediately in the corresponding scope */
uint16_t var_decls_count, /**< number of variable declarations immediately in the scope */
bool is_strict, /**< is the scope's code strict mode code? */
bool is_ref_arguments_identifier, /**< does the scope's code
* reference 'arguments' identifier? */
bool is_ref_eval_identifier, /**< does the scope's code
* reference 'eval' identifier? */
bool is_vars_and_args_to_regs_possible, /**< is it scope, for which variables / arguments
* can be moved to registers */
bool is_arguments_moved_to_regs, /**< is it function scope, for which arguments
* are located on registers, not in variables? */
bool is_no_lex_env) /**< is lexical environment unused in the scope? */
{
MEM_CP_SET_POINTER (bc_header_p->lit_id_hash_cp, lit_id_hash_table_p);
bc_header_p->instrs_p = bytecode_p;
bc_header_p->instrs_count = 0;
MEM_CP_SET_POINTER (bc_header_p->declarations_cp, declarations_p);
bc_header_p->func_scopes_count = func_scopes_count;
bc_header_p->var_decls_count = var_decls_count;
bc_header_p->next_header_cp = MEM_CP_NULL;
bc_header_p->is_strict = is_strict;
bc_header_p->is_ref_arguments_identifier = is_ref_arguments_identifier;
bc_header_p->is_ref_eval_identifier = is_ref_eval_identifier;
bc_header_p->is_vars_and_args_to_regs_possible = is_vars_and_args_to_regs_possible;
bc_header_p->is_args_moved_to_regs = is_arguments_moved_to_regs;
bc_header_p->is_no_lex_env = is_no_lex_env;
} /* bc_fill_bytecode_data_header */
/**
* Free memory occupied by bytecode data
*/
static void
bc_free_bytecode_data (bytecode_data_header_t *bytecode_data_p) /**< byte-code scope data header */
{
bytecode_data_header_t *next_to_handle_list_p = bytecode_data_p;
while (next_to_handle_list_p != NULL)
{
bytecode_data_header_t *bc_header_list_iter_p = next_to_handle_list_p;
next_to_handle_list_p = NULL;
while (bc_header_list_iter_p != NULL)
{
bytecode_data_header_t *header_p = bc_header_list_iter_p;
bc_header_list_iter_p = MEM_CP_GET_POINTER (bytecode_data_header_t, header_p->next_header_cp);
mem_cpointer_t *declarations_p = MEM_CP_GET_POINTER (mem_cpointer_t, header_p->declarations_cp);
for (uint32_t index = 0; index < header_p->func_scopes_count; index++)
{
bytecode_data_header_t *child_scope_header_p = MEM_CP_GET_NON_NULL_POINTER (bytecode_data_header_t,
declarations_p[index]);
JERRY_ASSERT (child_scope_header_p->next_header_cp == MEM_CP_NULL);
MEM_CP_SET_POINTER (child_scope_header_p->next_header_cp, next_to_handle_list_p);
next_to_handle_list_p = child_scope_header_p;
}
mem_heap_free_block (header_p);
}
JERRY_ASSERT (bc_header_list_iter_p == NULL);
}
} /* bc_free_bytecode_data */
/**
* Delete bytecode and associated hash table
*/
void
bc_remove_bytecode_data (const bytecode_data_header_t *bytecode_data_p) /**< byte-code scope data header */
{
bytecode_data_header_t *prev_header_p = NULL;
bytecode_data_header_t *cur_header_p = first_bytecode_header_p;
while (cur_header_p != NULL)
{
if (cur_header_p == bytecode_data_p)
{
if (prev_header_p)
{
prev_header_p->next_header_cp = cur_header_p->next_header_cp;
}
else
{
first_bytecode_header_p = MEM_CP_GET_POINTER (bytecode_data_header_t, cur_header_p->next_header_cp);
}
cur_header_p->next_header_cp = MEM_CP_NULL;
bc_free_bytecode_data (cur_header_p);
break;
}
prev_header_p = cur_header_p;
cur_header_p = MEM_CP_GET_POINTER (bytecode_data_header_t, cur_header_p->next_header_cp);
}
} /* bc_remove_bytecode_data */
vm_instr_t bc_get_instr (const bytecode_data_header_t *bytecode_data_p, /**< byte-code scope data header */
vm_instr_counter_t oc) /**< instruction position */
{
JERRY_ASSERT (oc < bytecode_data_p->instrs_count);
return bytecode_data_p->instrs_p[oc];
}
/**
* Print bytecode instructions
*/
void
bc_print_instrs (const bytecode_data_header_t *bytecode_data_p) /**< byte-code scope data header */
{
#ifdef JERRY_ENABLE_PRETTY_PRINTER
for (vm_instr_counter_t loc = 0; loc < bytecode_data_p->instrs_count; loc++)
{
op_meta opm;
opm.op = bytecode_data_p->instrs_p[loc];
for (int i = 0; i < 3; i++)
{
opm.lit_id[i] = NOT_A_LITERAL;
}
pp_op_meta (bytecode_data_p, loc, opm, false);
}
#else
(void) bytecode_data_p;
#endif
} /* bc_print_instrs */
/**
* Dump single scopes tree into bytecode
*
* @return pointer to bytecode header of the outer most scope
*/
bytecode_data_header_t *
bc_dump_single_scope (scopes_tree scope_p) /**< a node of scopes tree */
{
const size_t entries_count = scope_p->max_uniq_literals_num;
const vm_instr_counter_t instrs_count = scopes_tree_instrs_num (scope_p);
const size_t blocks_count = JERRY_ALIGNUP (instrs_count, BLOCK_SIZE) / BLOCK_SIZE;
const size_t func_scopes_count = scopes_tree_child_scopes_num (scope_p);
const uint16_t var_decls_count = linked_list_get_length (scope_p->var_decls);
const size_t bytecode_size = JERRY_ALIGNUP (instrs_count * sizeof (vm_instr_t), MEM_ALIGNMENT);
const size_t hash_table_size = lit_id_hash_table_get_size_for_table (entries_count, blocks_count);
const size_t declarations_area_size = JERRY_ALIGNUP (func_scopes_count * sizeof (mem_cpointer_t)
+ var_decls_count * sizeof (lit_cpointer_t),
MEM_ALIGNMENT);
const size_t header_and_tables_size = JERRY_ALIGNUP ((sizeof (bytecode_data_header_t)
+ hash_table_size
+ declarations_area_size),
MEM_ALIGNMENT);
uint8_t *buffer_p = (uint8_t *) mem_heap_alloc_block (bytecode_size + header_and_tables_size,
MEM_HEAP_ALLOC_LONG_TERM);
lit_id_hash_table *lit_id_hash_p = lit_id_hash_table_init (buffer_p + sizeof (bytecode_data_header_t),
hash_table_size,
entries_count, blocks_count);
mem_cpointer_t *declarations_p = (mem_cpointer_t *) (buffer_p + sizeof (bytecode_data_header_t) + hash_table_size);
for (size_t i = 0; i < func_scopes_count; i++)
{
declarations_p[i] = MEM_CP_NULL;
}
scopes_tree_dump_var_decls (scope_p, (lit_cpointer_t *) (declarations_p + func_scopes_count));
vm_instr_t *bytecode_p = (vm_instr_t *) (buffer_p + header_and_tables_size);
JERRY_ASSERT (scope_p->max_uniq_literals_num >= lit_id_hash_p->current_bucket_pos);
bytecode_data_header_t *header_p = (bytecode_data_header_t *) buffer_p;
if ((uint16_t) func_scopes_count != func_scopes_count)
{
jerry_fatal (ERR_OUT_OF_MEMORY);
}
bc_fill_bytecode_data_header (header_p,
lit_id_hash_p, bytecode_p,
declarations_p,
(uint16_t) func_scopes_count,
var_decls_count,
scope_p->strict_mode,
scope_p->ref_arguments,
scope_p->ref_eval,
scope_p->is_vars_and_args_to_regs_possible,
false,
false);
JERRY_ASSERT (scope_p->bc_header_cp == MEM_CP_NULL);
MEM_CP_SET_NON_NULL_POINTER (scope_p->bc_header_cp, header_p);
return header_p;
} /* bc_dump_single_scope */
void
bc_register_root_bytecode_header (bytecode_data_header_t *bc_header_p)
{
MEM_CP_SET_POINTER (bc_header_p->next_header_cp, first_bytecode_header_p);
first_bytecode_header_p = bc_header_p;
} /* bc_register_root_bytecode_header */
/**
* Free all bytecode data which was allocated
*/
void
bc_finalize (void)
{
while (first_bytecode_header_p != NULL)
{
bytecode_data_header_t *header_p = first_bytecode_header_p;
first_bytecode_header_p = MEM_CP_GET_POINTER (bytecode_data_header_t, header_p->next_header_cp);
header_p->next_header_cp = MEM_CP_NULL;
bc_free_bytecode_data (header_p);
}
} /* bc_finalize */
/**
* Convert literal id (operand value of instruction) to compressed pointer to literal
*
* Bytecode is divided into blocks of fixed size and each block has independent encoding of variable names,
* which are represented by 8 bit numbers - ids.
* This function performs conversion from id to literal.
*
* @return compressed pointer to literal
*/
lit_cpointer_t
bc_get_literal_cp_by_uid (uint8_t id, /**< literal idx */
const bytecode_data_header_t *bytecode_data_p, /**< pointer to bytecode */
vm_instr_counter_t oc) /**< position in the bytecode */
{
JERRY_ASSERT (bytecode_data_p);
lit_id_hash_table *lit_id_hash = MEM_CP_GET_POINTER (lit_id_hash_table, bytecode_data_p->lit_id_hash_cp);
if (lit_id_hash == NULL)
{
return INVALID_LITERAL;
}
return lit_id_hash_table_lookup (lit_id_hash, id, oc);
} /* bc_get_literal_cp_by_uid */
#ifdef JERRY_ENABLE_SNAPSHOT
/**
* Find literal offset in the table literal->offset
*/
uint32_t
bc_find_lit_offset (lit_cpointer_t lit_cp, /**< literal to find */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map from literal
* identifiers in
* literal storage
* to literal offsets
* in snapshot */
uint32_t literals_num) /**< number of entries in the map */
{
uint32_t lit_index;
for (lit_index = 0; lit_index < literals_num; lit_index++)
{
if (lit_map_p[lit_index].literal_id.packed_value == lit_cp.packed_value)
{
break;
}
}
JERRY_ASSERT (lit_index < literals_num);
return lit_map_p[lit_index].literal_offset;
} /* bc_find_lit_offset */
/**
* Write alignment bytes to outptut buffer to align 'in_out_size' to MEM_ALIGNEMENT
*
* @return true if alignment bytes were written successfully
* else otherwise
*/
bool
bc_align_data_in_output_buffer (uint32_t *in_out_size, /**< in: unaligned size, out: aligned size */
uint8_t *buffer_p, /**< buffer where to write */
size_t buffer_size, /**< buffer size */
size_t *in_out_buffer_offset_p) /**< current offset in buffer */
{
uint32_t aligned_size = JERRY_ALIGNUP (*in_out_size, MEM_ALIGNMENT);
if (aligned_size != (*in_out_size))
{
JERRY_ASSERT (aligned_size > (*in_out_size));
uint32_t padding_bytes_num = (uint32_t) (aligned_size - (*in_out_size));
uint8_t padding = 0;
for (uint32_t i = 0; i < padding_bytes_num; i++)
{
if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, &padding, sizeof (padding)))
{
return false;
}
}
*in_out_size = aligned_size;
}
return true;
} /* bc_align_data_in_output_buffer */
/**
* Dump byte-code and idx-to-literal map of a single scope to snapshot
*
* @return true, upon success (i.e. buffer size is enough),
* false - otherwise.
*/
static bool
bc_save_bytecode_with_idx_map (uint8_t *buffer_p, /**< buffer to dump to */
size_t buffer_size, /**< buffer size */
size_t *in_out_buffer_offset_p, /**< in-out: buffer write offset */
const bytecode_data_header_t *bytecode_data_p, /**< byte-code data */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map from literal
* identifiers in
* literal storage
* to literal offsets
* in snapshot */
uint32_t literals_num) /**< literals number */
{
JERRY_ASSERT (JERRY_ALIGNUP (*in_out_buffer_offset_p, MEM_ALIGNMENT) == *in_out_buffer_offset_p);
jerry_snapshot_bytecode_header_t bytecode_header;
bytecode_header.func_scopes_count = bytecode_data_p->func_scopes_count;
bytecode_header.var_decls_count = bytecode_data_p->var_decls_count;
bytecode_header.is_strict = bytecode_data_p->is_strict;
bytecode_header.is_ref_arguments_identifier = bytecode_data_p->is_ref_arguments_identifier;
bytecode_header.is_ref_eval_identifier = bytecode_data_p->is_ref_eval_identifier;
bytecode_header.is_args_moved_to_regs = bytecode_data_p->is_args_moved_to_regs;
bytecode_header.is_no_lex_env = bytecode_data_p->is_no_lex_env;
size_t bytecode_header_offset = *in_out_buffer_offset_p;
/* Dump instructions */
*in_out_buffer_offset_p += JERRY_ALIGNUP (sizeof (jerry_snapshot_bytecode_header_t), MEM_ALIGNMENT);
vm_instr_counter_t instrs_num = bytecode_data_p->instrs_count;
const size_t instrs_array_size = sizeof (vm_instr_t) * instrs_num;
if (*in_out_buffer_offset_p + instrs_array_size > buffer_size)
{
return false;
}
memcpy (buffer_p + *in_out_buffer_offset_p, bytecode_data_p->instrs_p, instrs_array_size);
*in_out_buffer_offset_p += instrs_array_size;
bytecode_header.instrs_size = (uint32_t) (sizeof (vm_instr_t) * instrs_num);
/* Dump variable declarations */
mem_cpointer_t *func_scopes_p = MEM_CP_GET_POINTER (mem_cpointer_t, bytecode_data_p->declarations_cp);
lit_cpointer_t *var_decls_p = (lit_cpointer_t *) (func_scopes_p + bytecode_data_p->func_scopes_count);
uint32_t null_var_decls_num = 0;
for (uint32_t i = 0; i < bytecode_header.var_decls_count; ++i)
{
lit_cpointer_t lit_cp = var_decls_p[i];
if (lit_cp.packed_value == MEM_CP_NULL)
{
null_var_decls_num++;
continue;
}
uint32_t offset = bc_find_lit_offset (lit_cp, lit_map_p, literals_num);
if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, &offset, sizeof (offset)))
{
return false;
}
}
bytecode_header.var_decls_count -= null_var_decls_num;
/* Dump uid->lit_cp hash table */
lit_id_hash_table *lit_id_hash_p = MEM_CP_GET_POINTER (lit_id_hash_table, bytecode_data_p->lit_id_hash_cp);
uint32_t idx_to_lit_map_size = lit_id_hash_table_dump_for_snapshot (buffer_p,
buffer_size,
in_out_buffer_offset_p,
lit_id_hash_p,
lit_map_p,
literals_num,
instrs_num);
if (idx_to_lit_map_size == 0)
{
return false;
}
bytecode_header.idx_to_lit_map_size = idx_to_lit_map_size;
/* Align to write next bytecode data at aligned address */
bytecode_header.size = (uint32_t) (*in_out_buffer_offset_p - bytecode_header_offset);
JERRY_ASSERT (bytecode_header.size == JERRY_ALIGNUP (sizeof (jerry_snapshot_bytecode_header_t), MEM_ALIGNMENT)
+ bytecode_header.instrs_size
+ bytecode_header.var_decls_count * sizeof (uint32_t)
+ idx_to_lit_map_size);
if (!bc_align_data_in_output_buffer (&bytecode_header.size,
buffer_p,
buffer_size,
in_out_buffer_offset_p))
{
return false;
}
/* Dump header at the saved offset */
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
&bytecode_header_offset,
&bytecode_header,
sizeof (bytecode_header)))
{
return false;
}
return true;
} /* bc_save_bytecode_with_idx_map */
/**
* Dump bytecode and summplementary data of all existing scopes to snapshot
*
* @return true if snapshot was dumped successfully
* false otherwise
*/
bool
bc_save_bytecode_data (uint8_t *buffer_p, /**< buffer to dump to */
size_t buffer_size, /**< buffer size */
size_t *in_out_buffer_offset_p, /**< in-out: buffer write offset */
const bytecode_data_header_t *bytecode_data_p, /**< byte-code data */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map from literal
* identifiers in
* literal storage
* to literal offsets
* in snapshot */
uint32_t literals_num, /**< literals number */
uint32_t *out_scopes_num) /**< number of scopes written */
{
bytecode_data_header_t *next_to_handle_list_p = first_bytecode_header_p;
while (next_to_handle_list_p != NULL)
{
if (next_to_handle_list_p == bytecode_data_p)
{
break;
}
next_to_handle_list_p = MEM_CP_GET_POINTER (bytecode_data_header_t, next_to_handle_list_p->next_header_cp);
}
JERRY_ASSERT (next_to_handle_list_p);
JERRY_ASSERT (next_to_handle_list_p->next_header_cp == MEM_CP_NULL);
*out_scopes_num = 0;
while (next_to_handle_list_p!= NULL)
{
bytecode_data_header_t *bc_header_list_iter_p = next_to_handle_list_p;
next_to_handle_list_p = NULL;
mem_cpointer_t *declarations_p = MEM_CP_GET_POINTER (mem_cpointer_t, bc_header_list_iter_p->declarations_cp);
if (!bc_save_bytecode_with_idx_map (buffer_p,
buffer_size,
in_out_buffer_offset_p,
bc_header_list_iter_p,
lit_map_p,
literals_num))
{
return false;
}
(*out_scopes_num)++;
next_to_handle_list_p = MEM_CP_GET_POINTER (bytecode_data_header_t, bc_header_list_iter_p->next_header_cp);
for (uint32_t index = bc_header_list_iter_p->func_scopes_count; index > 0 ; index--)
{
bytecode_data_header_t *child_scope_header_p = MEM_CP_GET_NON_NULL_POINTER (bytecode_data_header_t,
declarations_p[index-1]);
JERRY_ASSERT (child_scope_header_p->next_header_cp == MEM_CP_NULL);
MEM_CP_SET_POINTER (child_scope_header_p->next_header_cp, next_to_handle_list_p);
next_to_handle_list_p = child_scope_header_p;
}
bc_header_list_iter_p->next_header_cp = MEM_CP_NULL;
}
return true;
} /* bc_save_bytecode_data */
/**
* Register bytecode and supplementary data of a single scope from snapshot
*
* NOTE:
* If is_copy flag is set, bytecode is copied from snapshot, else bytecode is referenced directly
* from snapshot
*
* @return pointer to byte-code header, upon success,
* NULL - upon failure (i.e., in case snapshot format is not valid)
*/
static bytecode_data_header_t *
bc_load_bytecode_with_idx_map (const uint8_t *snapshot_data_p, /**< buffer with instructions array
* and idx to literals map from
* snapshot */
size_t snapshot_size, /**< remaining size of snapshot */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map of in-snapshot
* literal offsets
* to literal identifiers,
* created in literal
* storage */
uint32_t literals_num, /**< number of literals */
bool is_copy, /** flag, indicating whether the passed in-snapshot data
* should be copied to engine's memory (true),
* or it can be referenced until engine is stopped
* (i.e. until call to jerry_cleanup) */
uint32_t *out_bytecode_data_size) /**< out: size occupied by bytecode data
* in snapshot */
{
size_t buffer_offset = 0;
jerry_snapshot_bytecode_header_t bytecode_header;
if (!jrt_read_from_buffer_by_offset (snapshot_data_p,
snapshot_size,
&buffer_offset,
&bytecode_header,
sizeof (bytecode_header)))
{
return NULL;
}
*out_bytecode_data_size = bytecode_header.size;
buffer_offset += (JERRY_ALIGNUP (sizeof (jerry_snapshot_bytecode_header_t), MEM_ALIGNMENT)
- sizeof (jerry_snapshot_bytecode_header_t));
JERRY_ASSERT (bytecode_header.size <= snapshot_size);
/* Read uid->lit_cp hash table size */
const uint8_t *idx_to_lit_map_p = (snapshot_data_p
+ buffer_offset +
+ bytecode_header.instrs_size
+ bytecode_header.var_decls_count * sizeof (uint32_t));
size_t instructions_number = bytecode_header.instrs_size / sizeof (vm_instr_t);
size_t blocks_count = JERRY_ALIGNUP (instructions_number, BLOCK_SIZE) / BLOCK_SIZE;
uint32_t idx_num_total;
size_t idx_to_lit_map_offset = 0;
if (!jrt_read_from_buffer_by_offset (idx_to_lit_map_p,
bytecode_header.idx_to_lit_map_size,
&idx_to_lit_map_offset,
&idx_num_total,
sizeof (idx_num_total)))
{
return NULL;
}
/* Alloc bytecode_header for runtime */
const size_t bytecode_alloc_size = JERRY_ALIGNUP (bytecode_header.instrs_size, MEM_ALIGNMENT);
const size_t hash_table_size = lit_id_hash_table_get_size_for_table (idx_num_total, blocks_count);
const size_t declarations_area_size = JERRY_ALIGNUP (bytecode_header.func_scopes_count * sizeof (mem_cpointer_t)
+ bytecode_header.var_decls_count * sizeof (lit_cpointer_t),
MEM_ALIGNMENT);
const size_t header_and_tables_size = JERRY_ALIGNUP ((sizeof (bytecode_data_header_t)
+ hash_table_size
+ declarations_area_size),
MEM_ALIGNMENT);
const size_t alloc_size = header_and_tables_size + (is_copy ? bytecode_alloc_size : 0);
uint8_t *buffer_p = (uint8_t*) mem_heap_alloc_block (alloc_size, MEM_HEAP_ALLOC_LONG_TERM);
bytecode_data_header_t *header_p = (bytecode_data_header_t *) buffer_p;
vm_instr_t *instrs_p;
vm_instr_t *snapshot_instrs_p = (vm_instr_t *) (snapshot_data_p + buffer_offset);
if (is_copy)
{
instrs_p = (vm_instr_t *) (buffer_p + header_and_tables_size);
memcpy (instrs_p, snapshot_instrs_p, bytecode_header.instrs_size);
}
else
{
instrs_p = snapshot_instrs_p;
}
buffer_offset += bytecode_header.instrs_size; /* buffer_offset is now offset of variable declarations */
/* Read uid->lit_cp hash table */
uint8_t *lit_id_hash_table_buffer_p = buffer_p + sizeof (bytecode_data_header_t);
if (!(lit_id_hash_table_load_from_snapshot (blocks_count,
idx_num_total,
idx_to_lit_map_p + idx_to_lit_map_offset,
bytecode_header.idx_to_lit_map_size - idx_to_lit_map_offset,
lit_map_p,
literals_num,
lit_id_hash_table_buffer_p,
hash_table_size)
&& (vm_instr_counter_t) instructions_number == instructions_number))
{
mem_heap_free_block (buffer_p);
return NULL;
}
/* Fill with NULLs child scopes declarations for this scope */
mem_cpointer_t *declarations_p = (mem_cpointer_t *) (buffer_p + sizeof (bytecode_data_header_t) + hash_table_size);
memset (declarations_p, 0, bytecode_header.func_scopes_count * sizeof (mem_cpointer_t));
/* Read variable declarations for this scope */
lit_cpointer_t *var_decls_p = (lit_cpointer_t *) (declarations_p + bytecode_header.func_scopes_count);
for (uint32_t i = 0; i < bytecode_header.var_decls_count; i++)
{
uint32_t lit_offset_from_snapshot;
if (!jrt_read_from_buffer_by_offset (snapshot_data_p,
buffer_offset + bytecode_header.var_decls_count * sizeof (uint32_t),
&buffer_offset,
&lit_offset_from_snapshot,
sizeof (lit_offset_from_snapshot)))
{
mem_heap_free_block (buffer_p);
return NULL;
}
/**
* TODO: implement binary search here
*/
lit_cpointer_t lit_cp = NOT_A_LITERAL;
uint32_t j;
for (j = 0; j < literals_num; j++)
{
if (lit_map_p[j].literal_offset == lit_offset_from_snapshot)
{
lit_cp.packed_value = lit_map_p[j].literal_id.packed_value;
break;
}
}
if (j == literals_num)
{
mem_heap_free_block (buffer_p);
return NULL;
}
var_decls_p[i] = lit_cp;
}
/* Fill bytecode_data_header */
bc_fill_bytecode_data_header (header_p,
(lit_id_hash_table *) lit_id_hash_table_buffer_p,
instrs_p,
declarations_p,
(uint16_t) bytecode_header.func_scopes_count,
(uint16_t) bytecode_header.var_decls_count,
bytecode_header.is_strict,
bytecode_header.is_ref_arguments_identifier,
bytecode_header.is_ref_eval_identifier,
bytecode_header.is_args_moved_to_regs,
bytecode_header.is_args_moved_to_regs,
bytecode_header.is_no_lex_env);
return header_p;
} /* bc_load_bytecode_with_idx_map */
/**
* Register bytecode and supplementary data of all scopes from snapshot
*
* NOTE:
* If is_copy flag is set, bytecode is copied from snapshot, else bytecode is referenced directly
* from snapshot
*
* @return pointer to byte-code header, upon success,
* NULL - upon failure (i.e., in case snapshot format is not valid)
*/
const bytecode_data_header_t *
bc_load_bytecode_data (const uint8_t *snapshot_data_p, /**< buffer with instructions array
* and idx to literals map from
* snapshot */
size_t snapshot_size, /**< remaining size of snapshot */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map of in-snapshot
* literal offsets
* to literal identifiers,
* created in literal
* storage */
uint32_t literals_num, /**< number of literals */
bool is_copy, /** flag, indicating whether the passed in-snapshot data
* should be copied to engine's memory (true),
* or it can be referenced until engine is stopped
* (i.e. until call to jerry_cleanup) */
uint32_t expected_scopes_num) /**< scopes number read from snapshot header */
{
uint32_t snapshot_offset = 0;
uint32_t out_bytecode_data_size = 0;
uint32_t scopes_num = 0;
bytecode_data_header_t *bc_header_p = bc_load_bytecode_with_idx_map (snapshot_data_p,
snapshot_size,
lit_map_p,
literals_num,
is_copy,
&out_bytecode_data_size);
scopes_num++;
snapshot_offset += out_bytecode_data_size;
JERRY_ASSERT (snapshot_offset <= snapshot_size);
bytecode_data_header_t* next_to_handle_list_p = bc_header_p;
while (next_to_handle_list_p != NULL)
{
mem_cpointer_t *declarations_p = MEM_CP_GET_POINTER (mem_cpointer_t, next_to_handle_list_p->declarations_cp);
uint32_t child_scope_index = 0;
while (child_scope_index < next_to_handle_list_p->func_scopes_count
&& declarations_p[child_scope_index] != MEM_CP_NULL)
{
child_scope_index++;
}
if (child_scope_index == next_to_handle_list_p->func_scopes_count)
{
bytecode_data_header_t *bc_header_list_iter_p = MEM_CP_GET_POINTER (bytecode_data_header_t,
next_to_handle_list_p->next_header_cp);
next_to_handle_list_p->next_header_cp = MEM_CP_NULL;
next_to_handle_list_p = bc_header_list_iter_p;
if (next_to_handle_list_p == NULL)
{
break;
}
else
{
continue;
}
}
JERRY_ASSERT (snapshot_offset < snapshot_size);
bytecode_data_header_t *next_header_p = bc_load_bytecode_with_idx_map (snapshot_data_p + snapshot_offset,
snapshot_size - snapshot_offset,
lit_map_p,
literals_num,
is_copy,
&out_bytecode_data_size);
scopes_num++;
snapshot_offset += out_bytecode_data_size;
JERRY_ASSERT (snapshot_offset <= snapshot_size);
MEM_CP_SET_NON_NULL_POINTER (declarations_p[child_scope_index], next_header_p);
if (next_header_p->func_scopes_count > 0)
{
JERRY_ASSERT (next_header_p->next_header_cp == MEM_CP_NULL);
MEM_CP_SET_POINTER (next_header_p->next_header_cp, next_to_handle_list_p);
next_to_handle_list_p = next_header_p;
}
}
if (expected_scopes_num != scopes_num)
{
return NULL;
}
MEM_CP_SET_POINTER (bc_header_p->next_header_cp, first_bytecode_header_p);
first_bytecode_header_p = bc_header_p;
return bc_header_p;
} /* bc_load_bytecode_data */
#endif /* JERRY_ENABLE_SNAPSHOT */
-109
View File
@@ -1,109 +0,0 @@
/* Copyright 2014-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 BYTECODE_DATA_H
#define BYTECODE_DATA_H
#include "opcodes.h"
#include "mem-allocator.h"
#include "lit-id-hash-table.h"
#include "scopes-tree.h"
/*
* All literals are kept in the 'literals' array.
* Literal structure doesn't hold real string. All program-specific strings
* are kept in the 'strings_buffer' and literal has pointer to this buffer.
*
* Literal id is its index in 'literals' array of bytecode_data_t structure.
*
* Bytecode, which is kept in the 'instrs' field, is divided into blocks
* of 'BLOCK_SIZE' operands. Every block has its own numbering of literals.
* Literal uid could be in range [0, 127] in every block.
*
* To map uid to literal id 'lit_id_hash' table is used.
*/
#define BLOCK_SIZE 32u
/**
* Header of byte-code memory region, containing byte-code array and literal identifiers hash table
*/
typedef struct __attribute__ ((aligned (MEM_ALIGNMENT))) bytecode_data_header_t
{
vm_instr_t *instrs_p; /**< pointer to the bytecode */
vm_instr_counter_t instrs_count; /**< number of instructions in the byte-code array */
mem_cpointer_t lit_id_hash_cp; /**< pointer to literal identifiers hash table
* See also: lit_id_hash_table_init */
mem_cpointer_t declarations_cp; /**< function scopes and variable declarations inside current scope */
uint16_t func_scopes_count; /**< count of function scopes inside current scope */
uint16_t var_decls_count; /**< count of variable declrations inside current scope */
mem_cpointer_t next_header_cp; /**< pointer to next instructions data header */
uint8_t is_strict : 1; /**< code is strict mode code */
uint8_t is_ref_arguments_identifier : 1; /**< code doesn't reference 'arguments' identifier */
uint8_t is_ref_eval_identifier : 1; /**< code doesn't reference 'eval' identifier */
uint8_t is_vars_and_args_to_regs_possible : 1; /**< flag, indicating whether it is possible
* to safely perform var-to-reg
* optimization on the scope
*
* TODO: remove the flag when var-to-reg optimization
* would be moved from post-parse to dump stage */
uint8_t is_args_moved_to_regs : 1; /**< the function's arguments are moved to registers,
* so should be initialized in vm registers,
* and not in lexical environment */
uint8_t is_no_lex_env : 1; /**< no lex. env. is necessary for the scope */
} bytecode_data_header_t;
JERRY_STATIC_ASSERT (sizeof (bytecode_data_header_t) % MEM_ALIGNMENT == 0);
void bc_remove_bytecode_data (const bytecode_data_header_t *);
vm_instr_t bc_get_instr (const bytecode_data_header_t *,
vm_instr_counter_t);
void bc_print_instrs (const bytecode_data_header_t *);
bytecode_data_header_t *bc_dump_single_scope (scopes_tree);
void bc_register_root_bytecode_header (bytecode_data_header_t *);
void bc_finalize ();
lit_cpointer_t
bc_get_literal_cp_by_uid (uint8_t,
const bytecode_data_header_t *,
vm_instr_counter_t);
#ifdef JERRY_ENABLE_SNAPSHOT
/*
* Snapshot-related
*/
uint32_t
bc_find_lit_offset (lit_cpointer_t, const lit_mem_to_snapshot_id_map_entry_t *, uint32_t);
bool
bc_align_data_in_output_buffer (uint32_t *, uint8_t *, size_t, size_t *);
bool
bc_save_bytecode_data (uint8_t *, size_t, size_t *, const bytecode_data_header_t *,
const lit_mem_to_snapshot_id_map_entry_t *, uint32_t, uint32_t *);
const bytecode_data_header_t *
bc_load_bytecode_data (const uint8_t *, size_t,
const lit_mem_to_snapshot_id_map_entry_t *, uint32_t, bool, uint32_t);
#endif /* JERRY_ENABLE_SNAPSHOT */
#endif /* BYTECODE_DATA_H */
+78
View File
@@ -0,0 +1,78 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 "js-parser-internal.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_bytecode Bytecode
* @{
*/
#define CBC_OPCODE(arg1, arg2, arg3, arg4) \
((arg2) | (((arg3) + CBC_STACK_ADJUST_BASE) << CBC_STACK_ADJUST_SHIFT)),
/**
* Flags of the opcodes.
*/
const uint8_t cbc_flags[] =
{
CBC_OPCODE_LIST
};
/**
* Flags of the extended opcodes.
*/
const uint8_t cbc_ext_flags[] =
{
CBC_EXT_OPCODE_LIST
};
#undef CBC_OPCODE
#ifdef PARSER_DUMP_BYTE_CODE
#define CBC_OPCODE(arg1, arg2, arg3, arg4) #arg1,
/**
* Names of the opcodes.
*/
const char *cbc_names[] =
{
CBC_OPCODE_LIST
};
/**
* Names of the extended opcodes.
*/
const char *cbc_ext_names[] =
{
CBC_EXT_OPCODE_LIST
};
#undef CBC_OPCODE
#endif /* PARSER_DUMP_BYTE_CODE */
/**
* @}
* @}
* @}
*/
+694
View File
@@ -0,0 +1,694 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 BYTE_CODE_H
#define BYTE_CODE_H
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_bytecode Bytecode
* @{
*/
/**
* Compact byte code (CBC) is a byte code representation
* of EcmaScript which is designed for low memory
* environments. Most opcodes are only one or sometimes
* two byte long so the CBC provides a small binary size.
*
* The execution engine of CBC is a stack machine, where
* the maximum stack size is known in advance for each
* function.
*/
/**
* Byte code flags. Only the lower 5 bit can be used
* since the stack change is encoded in the upper
* three bits for each instruction between -4 and 3
* (except for call / construct opcodes).
*/
#define CBC_STACK_ADJUST_BASE 4
#define CBC_STACK_ADJUST_SHIFT 5
#define CBC_STACK_ADJUST_VALUE(value) \
(((value) >> CBC_STACK_ADJUST_SHIFT) - CBC_STACK_ADJUST_BASE)
#define CBC_NO_FLAG 0x00u
#define CBC_HAS_LITERAL_ARG 0x01u
#define CBC_HAS_LITERAL_ARG2 0x02u
#define CBC_HAS_BYTE_ARG 0x04u
#define CBC_HAS_BRANCH_ARG 0x08u
/* These flags are shared */
#define CBC_FORWARD_BRANCH_ARG 0x10u
#define CBC_POP_STACK_BYTE_ARG 0x10u
#define CBC_ARG_TYPES (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2 | CBC_HAS_BYTE_ARG | CBC_HAS_BRANCH_ARG)
#define CBC_HAS_POP_STACK_BYTE_ARG (CBC_HAS_BYTE_ARG | CBC_POP_STACK_BYTE_ARG)
/* Debug macro. */
#define CBC_ARGS_EQ(op, types) \
((cbc_flags[op] & CBC_ARG_TYPES) == (types))
/* Debug macro. */
#define CBC_SAME_ARGS(op1, op2) \
((cbc_flags[op1] & CBC_ARG_TYPES) == (cbc_flags[op2] & CBC_ARG_TYPES))
#define CBC_UNARY_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, 0, \
(VM_OC_ ## group) | VM_OC_GET_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _LITERAL, CBC_HAS_LITERAL_ARG, 1, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL | VM_OC_PUT_STACK)
#define CBC_BINARY_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, -1, \
(VM_OC_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _RIGHT_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
(VM_OC_ ## group) | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _TWO_LITERALS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL_LITERAL | VM_OC_PUT_STACK)
#define CBC_UNARY_LVALUE_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, -2, \
(VM_OC_PROP_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (name ## _PUSH_RESULT, CBC_NO_FLAG, -1, \
(VM_OC_PROP_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _BLOCK, CBC_NO_FLAG, -2, \
(VM_OC_PROP_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (name ## _IDENT, CBC_HAS_LITERAL_ARG, 0, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT) \
CBC_OPCODE (name ## _IDENT_PUSH_RESULT, CBC_HAS_LITERAL_ARG, 1, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _IDENT_BLOCK, CBC_HAS_LITERAL_ARG, 0, \
(VM_OC_ ## group) | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT | VM_OC_PUT_BLOCK)
#define CBC_BINARY_LVALUE_OPERATION(name, group) \
CBC_OPCODE (name, CBC_NO_FLAG, -4, \
(VM_OC_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (name ## _LITERAL, CBC_HAS_LITERAL_ARG, -3, \
(VM_OC_ ## group) | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_REFERENCE) \
#define CBC_EXT_BINARY_LVALUE_OPERATION(name, group) \
CBC_OPCODE (name ## _PUSH_RESULT, CBC_NO_FLAG, -3, \
(VM_OC_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (name ## _LITERAL_PUSH_RESULT, CBC_HAS_LITERAL_ARG, -2, \
(VM_OC_ ## group) | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
#define CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION(name, group) \
CBC_OPCODE (name ## _BLOCK, CBC_NO_FLAG, -4, \
(VM_OC_ ## group) | VM_OC_GET_STACK_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (name ## _LITERAL_BLOCK, CBC_HAS_LITERAL_ARG, -3, \
(VM_OC_ ## group) | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
#define CBC_UNARY_LVALUE_WITH_IDENT 3
#define CBC_BINARY_LVALUE_WITH_LITERAL 1
#define CBC_BINARY_WITH_LITERAL 1
#define CBC_BINARY_WITH_TWO_LITERALS 2
/**
* Several opcodes (mostly call and assignment opcodes) have
* two forms: one which does not push a return value onto
* the stack, and another which does. The reasion is that
* the return value of these opcodes are often not used
* and the first form provides smaller byte code.
*
* The following rules must be kept by the code generator:
* - only the opcode without return value can be emitted
* by the code generator
* - the first form can be converted to the second form
* by adding 1 to the opcode
* - after the conversion the opcode must be immediately
* flushed, so no further changes are possible
*
* Hence CBC_NO_RESULT_OPERATION (context_p->last_cbc_opcode)
* cannot be true for an opcode which has a result
*/
#define CBC_NO_RESULT_OPERATION(opcode) \
((opcode) >= CBC_DELETE && (opcode) < CBC_END)
#define CBC_NO_RESULT_BLOCK(opcode) \
((opcode) >= CBC_DELETE && (opcode) < CBC_ASSIGN_ADD)
#define CBC_NO_RESULT_COMPOUND_ASSIGMENT(opcode) \
((opcode) >= CBC_ASSIGN_ADD && (opcode) < CBC_END)
/**
* Branch instructions are organized in group of 8 opcodes.
* - 1st opcode: unused, can be used for other purpose
* - 2nd opcode: forward branch with 1 byte offset
* - 3rd opcode: forward branch with 2 byte offset
* - 4th opcode: forward branch with 3 byte offset
* - 5th opcode: unused, can be used for other purpose
* - 6th opcode: backward branch with 1 byte offset
* - 7th opcode: backward branch with 2 byte offset
* - 8th opcode: backward branch with 3 byte offset
*
* Reasons:
* The branch_opcode & 0x3 tells the length in bytes of the offset
* If branch offset & 0x4 == 0, it is a forward branch. Otherwise
* it is backward.
*
* The offset bytes are encoded in higher to lower order.
*/
#define CBC_FORWARD_BRANCH(name, stack, vm_oc) \
CBC_OPCODE (name, CBC_HAS_BRANCH_ARG | CBC_FORWARD_BRANCH_ARG, stack, \
(vm_oc)) \
CBC_OPCODE (name ## _2, CBC_HAS_BRANCH_ARG | CBC_FORWARD_BRANCH_ARG, stack, \
(vm_oc)) \
CBC_OPCODE (name ## _3, CBC_HAS_BRANCH_ARG | CBC_FORWARD_BRANCH_ARG, stack, \
(vm_oc))
#define CBC_BACKWARD_BRANCH(name, stack, vm_oc) \
CBC_OPCODE (name, CBC_HAS_BRANCH_ARG, stack, \
(vm_oc)) \
CBC_OPCODE (name ## _2, CBC_HAS_BRANCH_ARG, stack, \
(vm_oc)) \
CBC_OPCODE (name ## _3, CBC_HAS_BRANCH_ARG, stack, \
(vm_oc))
#define CBC_BRANCH_OFFSET_LENGTH(opcode) \
((opcode) & 0x3)
#define CBC_BRANCH_IS_BACKWARD(flags) \
(!((flags) & CBC_FORWARD_BRANCH_ARG))
#define CBC_BRANCH_IS_FORWARD(flags) \
((flags) & CBC_FORWARD_BRANCH_ARG)
/* Stack consumption of opcodes with context. */
/* PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION 3
/* PARSER_WITH_CONTEXT_STACK_ALLOCATION must be <= 4 */
#define PARSER_WITH_CONTEXT_STACK_ALLOCATION 2
/* PARSER_TRY_CONTEXT_STACK_ALLOCATION must be <= 3 */
#define PARSER_TRY_CONTEXT_STACK_ALLOCATION 2
/**
* Opcode definitions.
*/
#define CBC_OPCODE_LIST \
/* Branch opcodes first. Some other opcodes are mixed. */ \
CBC_OPCODE (CBC_EXT_OPCODE, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
CBC_FORWARD_BRANCH (CBC_JUMP_FORWARD, 0, \
VM_OC_JUMP) \
CBC_OPCODE (CBC_POP, CBC_NO_FLAG, -1, \
VM_OC_POP) \
CBC_BACKWARD_BRANCH (CBC_JUMP_BACKWARD, 0, \
VM_OC_JUMP) \
CBC_OPCODE (CBC_POP_BLOCK, CBC_NO_FLAG, -1, \
VM_OC_POP_BLOCK | VM_OC_PUT_BLOCK) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_TRUE_FORWARD, -1, \
VM_OC_BRANCH_IF_TRUE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_THROW, CBC_NO_FLAG, -1, \
VM_OC_THROW | VM_OC_GET_STACK) \
CBC_BACKWARD_BRANCH (CBC_BRANCH_IF_TRUE_BACKWARD, -1, \
VM_OC_BRANCH_IF_TRUE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_CONTEXT_END, CBC_NO_FLAG, 0, \
VM_OC_CONTEXT_END) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_FALSE_FORWARD, -1, \
VM_OC_BRANCH_IF_FALSE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_CREATE_OBJECT, CBC_NO_FLAG, 1, \
VM_OC_PUSH_OBJECT | VM_OC_PUT_STACK) \
CBC_BACKWARD_BRANCH (CBC_BRANCH_IF_FALSE_BACKWARD, -1, \
VM_OC_BRANCH_IF_FALSE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_SET_PROPERTY, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_SET_PROPERTY | VM_OC_GET_STACK_LITERAL) \
CBC_FORWARD_BRANCH (CBC_JUMP_FORWARD_EXIT_CONTEXT, 0, \
VM_OC_JUMP_AND_EXIT_CONTEXT) \
CBC_OPCODE (CBC_CREATE_ARRAY, CBC_NO_FLAG, 1, \
VM_OC_PUSH_ARRAY | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_LOGICAL_TRUE, -1, \
VM_OC_BRANCH_IF_LOGICAL_TRUE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_ARRAY_APPEND, CBC_HAS_POP_STACK_BYTE_ARG, 0, \
VM_OC_APPEND_ARRAY | VM_OC_GET_BYTE) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_LOGICAL_FALSE, -1, \
VM_OC_BRANCH_IF_LOGICAL_FALSE | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_PUSH_ELISION, CBC_NO_FLAG, 1, \
VM_OC_PUSH_ELISON | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_BRANCH_IF_STRICT_EQUAL, -1, \
VM_OC_BRANCH_IF_STRICT_EQUAL | VM_OC_GET_STACK) \
\
/* Basic opcodes. */ \
CBC_OPCODE (CBC_PUSH_LITERAL, CBC_HAS_LITERAL_ARG, 1, \
VM_OC_PUSH | VM_OC_GET_LITERAL) \
CBC_OPCODE (CBC_PUSH_TWO_LITERALS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 2, \
VM_OC_PUSH_TWO | VM_OC_GET_LITERAL_LITERAL) \
CBC_OPCODE (CBC_PUSH_THREE_LITERALS, CBC_HAS_LITERAL_ARG2, 3, \
VM_OC_PUSH_THREE | VM_OC_GET_LITERAL_LITERAL) \
CBC_OPCODE (CBC_PUSH_UNDEFINED, CBC_NO_FLAG, 1, \
VM_OC_PUSH_UNDEFINED | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_TRUE, CBC_NO_FLAG, 1, \
VM_OC_PUSH_TRUE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_FALSE, CBC_NO_FLAG, 1, \
VM_OC_PUSH_FALSE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NULL, CBC_NO_FLAG, 1, \
VM_OC_PUSH_NULL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_THIS, CBC_NO_FLAG, 1, \
VM_OC_PUSH_THIS | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_THIS_LITERAL, CBC_HAS_LITERAL_ARG, 2, \
VM_OC_PUSH_TWO | VM_OC_GET_THIS_LITERAL) \
CBC_OPCODE (CBC_PUSH_NUMBER_0, CBC_NO_FLAG, 1, \
VM_OC_PUSH_NUMBER | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_NUMBER_1, CBC_HAS_BYTE_ARG, 1, \
VM_OC_PUSH_NUMBER | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP, CBC_NO_FLAG, -1, \
VM_OC_PROP_GET | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_PROP_GET | VM_OC_GET_STACK_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL_LITERAL, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \
VM_OC_PROP_GET | VM_OC_GET_LITERAL_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_THIS_LITERAL, CBC_HAS_LITERAL_ARG, 1, \
VM_OC_PROP_GET | VM_OC_GET_THIS_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_IDENT_REFERENCE, CBC_HAS_LITERAL_ARG, 3, \
VM_OC_IDENT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_REFERENCE, CBC_NO_FLAG, 1, \
VM_OC_PROP_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL_REFERENCE, CBC_HAS_LITERAL_ARG, 2, \
VM_OC_PROP_REFERENCE | VM_OC_GET_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_LITERAL_LITERAL_REFERENCE, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 3, \
VM_OC_PROP_REFERENCE | VM_OC_GET_LITERAL_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_PUSH_PROP_THIS_LITERAL_REFERENCE, CBC_HAS_LITERAL_ARG, 3, \
VM_OC_PROP_REFERENCE | VM_OC_GET_THIS_LITERAL | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_NEW, CBC_HAS_POP_STACK_BYTE_ARG, 0, \
VM_OC_NEW | VM_OC_GET_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_NEW0, CBC_NO_FLAG, 0, \
VM_OC_NEW_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_NEW1, CBC_NO_FLAG, -1, \
VM_OC_NEW_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_EVAL, CBC_NO_FLAG, 0, \
VM_OC_EVAL) \
CBC_OPCODE (CBC_DEFINE_VARS, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_INITIALIZE_VAR, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_INITIALIZE_VARS, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_SET_BYTECODE_PTR, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
CBC_OPCODE (CBC_RETURN, CBC_NO_FLAG, -1, \
VM_OC_RET | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_RETURN_WITH_BLOCK, CBC_NO_FLAG, 0, \
VM_OC_RET) \
CBC_OPCODE (CBC_RETURN_WITH_LITERAL, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_RET | VM_OC_GET_LITERAL) \
\
/* Unary opcodes. */ \
CBC_UNARY_OPERATION (CBC_PLUS, \
PLUS) \
CBC_UNARY_OPERATION (CBC_NEGATE, \
MINUS) \
CBC_UNARY_OPERATION (CBC_LOGICAL_NOT, \
NOT) \
CBC_UNARY_OPERATION (CBC_BIT_NOT, \
BIT_NOT) \
CBC_UNARY_OPERATION (CBC_VOID, \
VOID) \
CBC_OPCODE (CBC_TYPEOF, CBC_NO_FLAG, 0, \
VM_OC_TYPEOF | VM_OC_GET_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_TYPEOF_IDENT, CBC_HAS_LITERAL_ARG, 1, \
VM_OC_TYPEOF_IDENT | VM_OC_PUT_STACK) \
\
/* Binary opcodes. */ \
CBC_BINARY_OPERATION (CBC_BIT_OR, \
BIT_OR) \
CBC_BINARY_OPERATION (CBC_BIT_XOR, \
BIT_XOR) \
CBC_BINARY_OPERATION (CBC_BIT_AND, \
BIT_AND) \
CBC_BINARY_OPERATION (CBC_EQUAL, \
EQUAL) \
CBC_BINARY_OPERATION (CBC_NOT_EQUAL, \
NOT_EQUAL) \
CBC_BINARY_OPERATION (CBC_STRICT_EQUAL, \
STRICT_EQUAL) \
CBC_BINARY_OPERATION (CBC_STRICT_NOT_EQUAL, \
STRICT_NOT_EQUAL) \
CBC_BINARY_OPERATION (CBC_LESS, \
LESS) \
CBC_BINARY_OPERATION (CBC_GREATER, \
GREATER) \
CBC_BINARY_OPERATION (CBC_LESS_EQUAL, \
LESS_EQUAL) \
CBC_BINARY_OPERATION (CBC_GREATER_EQUAL, \
GREATER_EQUAL) \
CBC_BINARY_OPERATION (CBC_IN, \
IN) \
CBC_BINARY_OPERATION (CBC_INSTANCEOF, \
INSTANCEOF) \
CBC_BINARY_OPERATION (CBC_LEFT_SHIFT, \
LEFT_SHIFT) \
CBC_BINARY_OPERATION (CBC_RIGHT_SHIFT, \
RIGHT_SHIFT) \
CBC_BINARY_OPERATION (CBC_UNS_RIGHT_SHIFT, \
UNS_RIGHT_SHIFT) \
CBC_BINARY_OPERATION (CBC_ADD, \
ADD) \
CBC_BINARY_OPERATION (CBC_SUBTRACT, \
SUB) \
CBC_BINARY_OPERATION (CBC_MULTIPLY, \
MUL) \
CBC_BINARY_OPERATION (CBC_DIVIDE, \
DIV) \
CBC_BINARY_OPERATION (CBC_MODULO, \
MOD) \
\
/* Unary lvalue opcodes. */ \
CBC_OPCODE (CBC_DELETE, CBC_NO_FLAG, -2, \
VM_OC_PROP_DELETE | VM_OC_GET_STACK_STACK) \
CBC_OPCODE (CBC_DELETE_PUSH_RESULT, CBC_NO_FLAG, -1, \
VM_OC_PROP_DELETE | VM_OC_GET_STACK_STACK | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_DELETE_BLOCK, CBC_NO_FLAG, -2, \
VM_OC_PROP_DELETE | VM_OC_GET_STACK_STACK | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_DELETE_IDENT, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_DELETE) \
CBC_OPCODE (CBC_DELETE_IDENT_PUSH_RESULT, CBC_HAS_LITERAL_ARG, 1, \
VM_OC_DELETE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_DELETE_IDENT_BLOCK, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_DELETE | VM_OC_PUT_BLOCK) \
CBC_UNARY_LVALUE_OPERATION (CBC_PRE_INCR, \
PRE_INCR) \
CBC_UNARY_LVALUE_OPERATION (CBC_PRE_DECR, \
PRE_DECR) \
CBC_UNARY_LVALUE_OPERATION (CBC_POST_INCR, \
POST_INCR) \
CBC_UNARY_LVALUE_OPERATION (CBC_POST_DECR, \
POST_DECR) \
\
/* Call opcodes. */ \
CBC_OPCODE (CBC_CALL, CBC_HAS_POP_STACK_BYTE_ARG, -1, \
VM_OC_CALL | VM_OC_GET_BYTE) \
CBC_OPCODE (CBC_CALL_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, 0, \
VM_OC_CALL | VM_OC_GET_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -1, \
VM_OC_CALL | VM_OC_GET_BYTE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL_PROP, CBC_HAS_POP_STACK_BYTE_ARG, -3, \
VM_OC_CALL_PROP | VM_OC_GET_BYTE) \
CBC_OPCODE (CBC_CALL_PROP_PUSH_RESULT, CBC_HAS_POP_STACK_BYTE_ARG, -2, \
VM_OC_CALL_PROP | VM_OC_GET_BYTE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL_PROP_BLOCK, CBC_HAS_POP_STACK_BYTE_ARG, -3, \
VM_OC_CALL_PROP | VM_OC_GET_BYTE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL0, CBC_NO_FLAG, -1, \
VM_OC_CALL_N) \
CBC_OPCODE (CBC_CALL0_PUSH_RESULT, CBC_NO_FLAG, 0, \
VM_OC_CALL_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL0_BLOCK, CBC_NO_FLAG, -1, \
VM_OC_CALL_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL0_PROP, CBC_NO_FLAG, -3, \
VM_OC_CALL_PROP_N) \
CBC_OPCODE (CBC_CALL0_PROP_PUSH_RESULT, CBC_NO_FLAG, -2, \
VM_OC_CALL_PROP_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL0_PROP_BLOCK, CBC_NO_FLAG, -3, \
VM_OC_CALL_PROP_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL1, CBC_NO_FLAG, -2, \
VM_OC_CALL_N) \
CBC_OPCODE (CBC_CALL1_PUSH_RESULT, CBC_NO_FLAG, -1, \
VM_OC_CALL_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL1_BLOCK, CBC_NO_FLAG, -2, \
VM_OC_CALL_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL1_PROP, CBC_NO_FLAG, -4, \
VM_OC_CALL_PROP_N) \
CBC_OPCODE (CBC_CALL1_PROP_PUSH_RESULT, CBC_NO_FLAG, -3, \
VM_OC_CALL_PROP_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL1_PROP_BLOCK, CBC_NO_FLAG, -4, \
VM_OC_CALL_PROP_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL2, CBC_NO_FLAG, -3, \
VM_OC_CALL_N) \
CBC_OPCODE (CBC_CALL2_PUSH_RESULT, CBC_NO_FLAG, -2, \
VM_OC_CALL_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL2_BLOCK, CBC_NO_FLAG, -3, \
VM_OC_CALL_N | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_CALL2_PROP, CBC_NO_FLAG, -4, \
VM_OC_CALL_PROP_N) \
CBC_OPCODE (CBC_CALL2_PROP_PUSH_RESULT, CBC_NO_FLAG, -3, \
VM_OC_CALL_PROP_N | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_CALL2_PROP_BLOCK, CBC_NO_FLAG, -4, \
VM_OC_CALL_PROP_N | VM_OC_PUT_BLOCK) \
\
/* Binary assignment opcodes. */ \
CBC_OPCODE (CBC_ASSIGN, CBC_NO_FLAG, -3, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (CBC_ASSIGN_PUSH_RESULT, CBC_NO_FLAG, -2, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_BLOCK, CBC_NO_FLAG, -3, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_ASSIGN_SET_IDENT, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_IDENT) \
CBC_OPCODE (CBC_ASSIGN_SET_IDENT_PUSH_RESULT, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_IDENT | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_SET_IDENT_BLOCK, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN | VM_OC_GET_STACK | VM_OC_PUT_IDENT | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_ASSIGN_LITERAL_SET_IDENT, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_ASSIGN | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT) \
CBC_OPCODE (CBC_ASSIGN_LITERAL_SET_IDENT_PUSH_RESULT, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 1, \
VM_OC_ASSIGN | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_LITERAL_SET_IDENT_BLOCK, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_ASSIGN | VM_OC_GET_LITERAL | VM_OC_PUT_IDENT | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_ASSIGN_PROP_LITERAL, CBC_HAS_LITERAL_ARG, -2, \
VM_OC_ASSIGN_PROP | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (CBC_ASSIGN_PROP_LITERAL_PUSH_RESULT, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN_PROP | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_PROP_LITERAL_BLOCK, CBC_HAS_LITERAL_ARG, -2, \
VM_OC_ASSIGN_PROP | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
CBC_OPCODE (CBC_ASSIGN_PROP_THIS_LITERAL, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN_PROP_THIS | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE) \
CBC_OPCODE (CBC_ASSIGN_PROP_THIS_LITERAL_PUSH_RESULT, CBC_HAS_LITERAL_ARG, 0, \
VM_OC_ASSIGN_PROP_THIS | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_STACK) \
CBC_OPCODE (CBC_ASSIGN_PROP_THIS_LITERAL_BLOCK, CBC_HAS_LITERAL_ARG, -1, \
VM_OC_ASSIGN_PROP_THIS | VM_OC_GET_LITERAL | VM_OC_PUT_REFERENCE | VM_OC_PUT_BLOCK) \
\
/* Binary compound assignment opcodes. */ \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_ADD, \
ADD) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_SUBTRACT, \
SUB) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_MULTIPLY, \
MUL) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_DIVIDE, \
DIV) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_MODULO, \
MOD) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_LEFT_SHIFT, \
LEFT_SHIFT) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_RIGHT_SHIFT, \
RIGHT_SHIFT) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_UNS_RIGHT_SHIFT, \
UNS_RIGHT_SHIFT) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_BIT_AND, \
BIT_AND) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_BIT_OR, \
BIT_OR) \
CBC_BINARY_LVALUE_OPERATION (CBC_ASSIGN_BIT_XOR, \
BIT_XOR) \
\
/* Last opcode (not a real opcode). */ \
CBC_OPCODE (CBC_END, CBC_NO_FLAG, 0, \
VM_OC_NONE)
/* All EXT branches are statement block end
* marks, so they are always forward branches. */
#define CBC_EXT_OPCODE_LIST \
/* Branch opcodes first. Some other opcodes are mixed. */ \
CBC_OPCODE (CBC_EXT_NOP, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
CBC_FORWARD_BRANCH (CBC_EXT_WITH_CREATE_CONTEXT, \
-1 + PARSER_WITH_CONTEXT_STACK_ALLOCATION, VM_OC_WITH | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_EXT_FOR_IN_GET_NEXT, CBC_NO_FLAG, 1, \
VM_OC_FOR_IN_GET_NEXT | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_EXT_FOR_IN_CREATE_CONTEXT, \
-1 + PARSER_FOR_IN_CONTEXT_STACK_ALLOCATION, VM_OC_FOR_IN_CREATE_CONTEXT | VM_OC_GET_STACK) \
CBC_OPCODE (CBC_EXT_SET_GETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_SET_GETTER | VM_OC_GET_LITERAL_LITERAL) \
CBC_BACKWARD_BRANCH (CBC_EXT_BRANCH_IF_FOR_IN_HAS_NEXT, 0, \
VM_OC_FOR_IN_HAS_NEXT) \
CBC_OPCODE (CBC_EXT_SET_SETTER, CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2, 0, \
VM_OC_SET_SETTER | VM_OC_GET_LITERAL_LITERAL) \
CBC_FORWARD_BRANCH (CBC_EXT_TRY_CREATE_CONTEXT, PARSER_TRY_CONTEXT_STACK_ALLOCATION, \
VM_OC_TRY) \
CBC_OPCODE (CBC_EXT_THROW_REFERENCE_ERROR, CBC_NO_FLAG, 1, \
VM_OC_THROW_REFERENCE_ERROR) \
CBC_FORWARD_BRANCH (CBC_EXT_CATCH, 1, \
VM_OC_CATCH) \
CBC_OPCODE (CBC_EXT_PUSH_UNDEFINED_BASE, CBC_NO_FLAG, 1, \
VM_OC_PUSH_UNDEFINED_BASE | VM_OC_PUT_STACK) \
CBC_FORWARD_BRANCH (CBC_EXT_FINALLY, 0, \
VM_OC_FINALLY) \
\
/* Basic opcodes. */ \
CBC_OPCODE (CBC_EXT_DEBUGGER, CBC_NO_FLAG, 0, \
VM_OC_NONE) \
\
/* Binary compound assignment opcodes with pushing the result. */ \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_ADD, \
ADD) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_SUBTRACT, \
SUB) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_MULTIPLY, \
MUL) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_DIVIDE, \
DIV) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_MODULO, \
MOD) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_LEFT_SHIFT, \
LEFT_SHIFT) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_RIGHT_SHIFT, \
RIGHT_SHIFT) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_UNS_RIGHT_SHIFT, \
UNS_RIGHT_SHIFT) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_BIT_AND, \
BIT_AND) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_BIT_OR, \
BIT_OR) \
CBC_EXT_BINARY_LVALUE_OPERATION (CBC_EXT_ASSIGN_BIT_XOR, \
BIT_XOR) \
\
/* Binary compound assignment opcodes with saving the result. */ \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_ADD, \
ADD) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_SUBTRACT, \
SUB) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_MULTIPLY, \
MUL) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_DIVIDE, \
DIV) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_MODULO, \
MOD) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_LEFT_SHIFT, \
LEFT_SHIFT) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_RIGHT_SHIFT, \
RIGHT_SHIFT) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_UNS_RIGHT_SHIFT, \
UNS_RIGHT_SHIFT) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_BIT_AND, \
BIT_AND) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_BIT_OR, \
BIT_OR) \
CBC_EXT_BINARY_LVALUE_BLOCK_OPERATION (CBC_EXT_ASSIGN_BIT_XOR, \
BIT_XOR) \
\
/* Last opcode (not a real opcode). */ \
CBC_OPCODE (CBC_EXT_END, CBC_NO_FLAG, 0, \
VM_OC_NONE)
#define CBC_MAXIMUM_BYTE_VALUE 255
#define CBC_MAXIMUM_SMALL_VALUE 510
#define CBC_MAXIMUM_FULL_VALUE 32767
#define CBC_PUSH_NUMBER_1_RANGE_END 128
#define CBC_HIGHEST_BIT_MASK 0x80
#define CBC_LOWER_SEVEN_BIT_MASK 0x7f
/**
* Literal indicies belong to one of the following groups:
*
* 0 <= index < argument_end : arguments
* argument_end <= index < register_end : registers
* register_end <= index < ident_end : identifiers
* ident_end <= index < const_literal_end : constant literals
* const_literal_end <= index < literal_end : template literals
*/
/**
* Compiled byte code arguments.
*/
typedef struct
{
uint16_t status_flags; /**< various status flags */
uint8_t stack_limit; /**< maximum number of values stored on the stack */
uint8_t argument_end; /**< number of arguments expected by the function */
uint8_t register_end; /**< end position of the register group */
uint8_t ident_end; /**< end position of the identifier group */
uint8_t const_literal_end; /**< end position of the const literal group */
uint8_t literal_end; /**< end position of the literal group */
} cbc_uint8_arguments_t;
/**
* Compiled byte code arguments.
*/
typedef struct
{
uint16_t status_flags; /**< various status flags */
uint16_t stack_limit; /**< maximum number of values stored on the stack */
uint16_t argument_end; /**< number of arguments expected by the function */
uint16_t register_end; /**< end position of the register group */
uint16_t ident_end; /**< end position of the identifier group */
uint16_t const_literal_end; /**< end position of the const literal group */
uint16_t literal_end; /**< end position of the literal group */
} cbc_uint16_arguments_t;
/* When CBC_CODE_FLAGS_FULL_LITERAL_ENCODING
* is not set the small encoding is used. */
#define CBC_CODE_FLAGS_FUNCTION 0x01
#define CBC_CODE_FLAGS_FULL_LITERAL_ENCODING 0x02
#define CBC_CODE_FLAGS_UINT16_ARGUMENTS 0x04
#define CBC_CODE_FLAGS_STRICT_MODE 0x08
#define CBC_CODE_FLAGS_ARGUMENTS_NEEDED 0x10
#define CBC_CODE_FLAGS_LEXICAL_ENV_NOT_NEEDED 0x20
#define CBC_OPCODE(arg1, arg2, arg3, arg4) arg1,
/**
* Opcode list.
*/
typedef enum
{
CBC_OPCODE_LIST /**< list of opcodes */
} cbc_opcode_t;
/**
* Extended opcode list.
*/
typedef enum
{
CBC_EXT_OPCODE_LIST /**< list extended opcodes */
} cbc_ext_opcode_t;
#undef CBC_OPCODE
/**
* Opcode flags.
*/
extern const uint8_t cbc_flags[];
extern const uint8_t cbc_ext_flags[];
#ifdef PARSER_DUMP_BYTE_CODE
/**
* Opcode names for debugging.
*/
extern const char *cbc_names[];
extern const char *cbc_ext_names[];
#endif /* PARSER_DUMP_BYTE_CODE */
/**
* @}
* @}
* @}
*/
#endif /* !BYTE_CODE_H */
@@ -1,135 +0,0 @@
/* Copyright 2014-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 "array-list.h"
#include "jrt-libc-includes.h"
#include "jsp-mm.h"
typedef struct
{
uint8_t element_size;
size_t len;
size_t size;
} array_list_header;
static array_list_header *
extract_header (array_list al)
{
JERRY_ASSERT (al != null_list);
array_list_header *header = (array_list_header *) al;
return header;
}
static uint8_t *
data (array_list al)
{
return (uint8_t *) al + sizeof (array_list_header);
}
array_list
array_list_append (array_list al, void *element)
{
array_list_header *h = extract_header (al);
if ((h->len + 1) * h->element_size + sizeof (array_list_header) > h->size)
{
size_t size = jsp_mm_recommend_size (h->size + h->element_size);
JERRY_ASSERT (size > h->size);
uint8_t *new_block_p = (uint8_t *) jsp_mm_alloc (size);
memcpy (new_block_p, h, h->size);
memset (new_block_p + h->size, 0, size - h->size);
jsp_mm_free (h);
h = (array_list_header *) new_block_p;
h->size = size;
al = (array_list) h;
}
memcpy (data (al) + (h->len * h->element_size), element, h->element_size);
h->len++;
return al;
}
void
array_list_drop_last (array_list al)
{
array_list_header *h = extract_header (al);
JERRY_ASSERT (h->len > 0);
h->len--;
}
void *
array_list_element (array_list al, size_t index)
{
array_list_header *h = extract_header (al);
if (h->len <= index)
{
return NULL;
}
return data (al) + (index * h->element_size);
}
void
array_list_set_element (array_list al, size_t index, void *elem)
{
array_list_header *h = extract_header (al);
JERRY_ASSERT (index < h->len);
memcpy (data (al) + (index * h->element_size), elem, h->element_size);
}
void *
array_list_last_element (array_list al, size_t index)
{
array_list_header *h = extract_header (al);
if (index == 0 || index > h->len)
{
return NULL;
}
return array_list_element (al, (size_t) (h->len - index));
}
void
array_list_set_last_element (array_list al, size_t index, void *elem)
{
array_list_header *h = extract_header (al);
JERRY_ASSERT (index != 0 && index <= h->len);
array_list_set_element (al, (size_t) (h->len - index), elem);
}
array_list
array_list_init (uint8_t element_size)
{
size_t size = jsp_mm_recommend_size (sizeof (array_list_header));
array_list_header *header = (array_list_header *) jsp_mm_alloc (size);
memset (header, 0, size);
header->element_size = element_size;
header->len = 0;
header->size = size;
return (array_list) header;
}
size_t
array_list_len (array_list al)
{
array_list_header *h = extract_header (al);
return h->len;
}
void
array_list_free (array_list al)
{
array_list_header *h = extract_header (al);
jsp_mm_free (h);
}
@@ -1,34 +0,0 @@
/* Copyright 2014-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 ARRAY_LIST_H
#define ARRAY_LIST_H
#include "jrt.h"
typedef uint8_t *array_list;
#define null_list NULL
array_list array_list_init (uint8_t);
void array_list_free (array_list);
array_list array_list_append (array_list, void *);
void array_list_drop_last (array_list);
void *array_list_element (array_list, size_t);
void array_list_set_element (array_list, size_t, void *);
void *array_list_last_element (array_list, size_t);
void array_list_set_last_element (array_list, size_t, void *);
size_t array_list_len (array_list);
#endif /* ARRAY_LIST_H */
@@ -1,334 +0,0 @@
/* Copyright 2014-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 "jrt-libc-includes.h"
#include "jsp-mm.h"
#include "linked-list.h"
/**
* Header of a linked list's chunk
*/
typedef struct linked_list_chunk_header
{
struct linked_list_chunk_header *next_p; /**< pointer to next chunk of the list */
} linked_list_chunk_header;
/**
* Header of a linked list
*/
typedef struct
{
uint16_t list_length; /**< number of elements */
uint16_t element_size; /**< size of an element */
} linked_list_header;
#define ASSERT_LIST(list) \
do { \
linked_list_header *header = (linked_list_header *) list; \
JERRY_ASSERT (header); \
} while (0);
/**
* Calculate size of a linked list's chunk
*
* @return size of the chunk's data space
*/
static size_t
linked_list_block_size (bool is_first_chunk) /**< is it first chunk (chunk, containing header)? */
{
if (is_first_chunk)
{
return (jsp_mm_recommend_size (sizeof (linked_list_header) + sizeof (linked_list_chunk_header) + 1u)
- sizeof (linked_list_header) - sizeof (linked_list_chunk_header));
}
else
{
return (jsp_mm_recommend_size (sizeof (linked_list_chunk_header) + 1u) - sizeof (linked_list_chunk_header));
}
} /* linked_list_block_size */
/**
* Initialize linked list
*
* @return linked list's identifier
*/
linked_list
linked_list_init (size_t element_size) /**< size of a linked list's element */
{
JERRY_ASSERT (element_size <= linked_list_block_size (true));
size_t size = sizeof (linked_list_header) + sizeof (linked_list_chunk_header) + linked_list_block_size (true);
linked_list list = (linked_list) jsp_mm_alloc (size);
JERRY_ASSERT (list != null_list);
linked_list_header *header_p = (linked_list_header *) list;
header_p->element_size = (uint16_t) element_size;
JERRY_ASSERT (header_p->element_size == element_size);
header_p->list_length = 0;
linked_list_chunk_header* chunk_header_p = (linked_list_chunk_header *) (header_p + 1u);
chunk_header_p->next_p = NULL;
return list;
} /* linked_list_init */
/**
* Create and append new chunk to list
*
* @return pointer to the new chunk
*/
static linked_list_chunk_header *
linked_list_append_new_chunk (linked_list_header *header_p, /**< linked list's header */
linked_list_chunk_header *last_chunk_header_p) /**< last chunk of the list */
{
JERRY_ASSERT (header_p != NULL && last_chunk_header_p != NULL);
JERRY_ASSERT (header_p->element_size <= linked_list_block_size (false));
size_t size = sizeof (linked_list_chunk_header) + linked_list_block_size (false);
linked_list_chunk_header *new_chunk_header_p = (linked_list_chunk_header *) jsp_mm_alloc (size);
JERRY_ASSERT (new_chunk_header_p != NULL);
new_chunk_header_p->next_p = NULL;
JERRY_ASSERT (last_chunk_header_p->next_p == NULL);
last_chunk_header_p->next_p = new_chunk_header_p;
return new_chunk_header_p;
} /* linked_list_append_new_chunk */
/**
* Free the linked list
*/
void
linked_list_free (linked_list list) /**< linked list's identifier */
{
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
linked_list_chunk_header *first_chunk_header_p = (linked_list_chunk_header *) (header_p + 1u);
linked_list_chunk_header *iter_p = first_chunk_header_p->next_p;
while (iter_p != NULL)
{
linked_list_chunk_header *iter_next_p = iter_p->next_p;
jsp_mm_free (iter_p);
iter_p = iter_next_p;
}
jsp_mm_free (header_p);
} /* linked_list_free */
/**
* Get pointer to next element of the list
*
* @return pointer to the next element's area,
* or NULL - in case end of list was reached.
*/
static uint8_t*
linked_list_switch_to_next_elem (linked_list_header *header_p, /**< list header */
linked_list_chunk_header **in_out_chunk_header_p, /**< list iterator (in case end
* of list was reached,
* the iterator points
* to last chunk of the list) */
uint8_t *raw_elem_ptr_p) /**< element to get the next element for */
{
linked_list_chunk_header *chunk_header_p = *in_out_chunk_header_p;
const size_t element_size = header_p->element_size;
const bool is_first_chunk = ((linked_list_chunk_header *) (header_p + 1u) == chunk_header_p);
JERRY_ASSERT (raw_elem_ptr_p + element_size
<= (uint8_t *) (chunk_header_p + 1u) + linked_list_block_size (is_first_chunk));
const size_t elements_in_chunk = linked_list_block_size (is_first_chunk) / element_size;
uint8_t *raw_start_p = (uint8_t *) (chunk_header_p + 1u);
JERRY_ASSERT (raw_elem_ptr_p >= raw_start_p);
size_t element_offset = (size_t) (raw_elem_ptr_p - raw_start_p) / element_size;
if (element_offset == elements_in_chunk - 1)
{
linked_list_chunk_header *next_chunk_header_p = chunk_header_p->next_p;
if (next_chunk_header_p == NULL)
{
return NULL;
}
else
{
*in_out_chunk_header_p = next_chunk_header_p;
return (uint8_t *) (next_chunk_header_p + 1u);
}
}
else
{
JERRY_ASSERT (element_offset < elements_in_chunk - 1u);
return (raw_elem_ptr_p + element_size);
}
} /* linked_list_switch_to_next_elem */
/**
* Get pointer to the linked list's element
*/
void *
linked_list_element (linked_list list, /**< linked list's identifier */
size_t element_num) /**< index of the element */
{
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
if (element_num >= header_p->list_length)
{
return NULL;
}
linked_list_chunk_header *list_chunk_iter_p = (linked_list_chunk_header *) (header_p + 1u);
uint8_t *element_iter_p = (uint8_t *) (list_chunk_iter_p + 1);
for (size_t i = 0; i < element_num; i++)
{
element_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p);
if (element_iter_p == NULL)
{
return NULL;
}
}
return element_iter_p;
} /* linked_list_element */
/**
* Set linked list's element
*/
void
linked_list_set_element (linked_list list, /**< linked list's identifier */
size_t element_num, /**< index of element to set */
void *element_p) /**< pointer to new value of the element */
{
if (element_p == NULL)
{
return;
}
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
linked_list_chunk_header *list_chunk_iter_p = (linked_list_chunk_header *) (header_p + 1u);
uint8_t *element_iter_p = (uint8_t *) (list_chunk_iter_p + 1u);
for (size_t i = 0; i < element_num; i++)
{
element_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p);
if (element_iter_p == NULL)
{
JERRY_ASSERT (element_num >= header_p->list_length);
linked_list_append_new_chunk (header_p, list_chunk_iter_p);
list_chunk_iter_p = list_chunk_iter_p->next_p;
element_iter_p = (uint8_t *) (list_chunk_iter_p + 1u);
}
}
if (element_num + 1 > header_p->list_length)
{
header_p->list_length = (uint16_t) (element_num + 1u);
JERRY_ASSERT (header_p->list_length == element_num + 1u);
}
JERRY_ASSERT (element_iter_p != NULL);
memcpy (element_iter_p, element_p, header_p->element_size);
} /* linked_list_set_element */
/**
* Remove specified element from the linked list
*/
void
linked_list_remove_element (linked_list list, /**< linked list's identifier */
size_t element_num) /**< position of the element */
{
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
linked_list_chunk_header *list_chunk_iter_p = (linked_list_chunk_header *) (header_p + 1u);
linked_list_chunk_header *chunk_prev_to_chunk_with_last_elem_p = list_chunk_iter_p;
const size_t list_length = header_p->list_length;
const size_t element_size = header_p->element_size;
JERRY_ASSERT (element_num < list_length);
uint8_t *element_iter_p = (uint8_t *) (list_chunk_iter_p + 1u);
for (size_t i = 0; i < element_num; i++)
{
chunk_prev_to_chunk_with_last_elem_p = list_chunk_iter_p;
element_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p);
JERRY_ASSERT (element_iter_p != NULL);
}
uint8_t *next_elem_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, element_iter_p);
JERRY_ASSERT ((element_num + 1 == list_length && next_elem_iter_p == NULL)
|| (next_elem_iter_p != NULL));
for (size_t i = element_num + 1; i < list_length; i++)
{
JERRY_ASSERT (next_elem_iter_p != NULL);
memcpy (element_iter_p, next_elem_iter_p, element_size);
chunk_prev_to_chunk_with_last_elem_p = list_chunk_iter_p;
element_iter_p = next_elem_iter_p;
next_elem_iter_p = linked_list_switch_to_next_elem (header_p, &list_chunk_iter_p, next_elem_iter_p);
}
if (list_chunk_iter_p != chunk_prev_to_chunk_with_last_elem_p)
{
JERRY_ASSERT (chunk_prev_to_chunk_with_last_elem_p->next_p == list_chunk_iter_p);
jsp_mm_free (list_chunk_iter_p);
chunk_prev_to_chunk_with_last_elem_p->next_p = NULL;
}
header_p->list_length--;
} /* linked_list_remove_element */
/**
* Get length of the linked list
*
* @return length
*/
uint16_t
linked_list_get_length (linked_list list) /**< linked list's identifier */
{
ASSERT_LIST (list);
linked_list_header *header_p = (linked_list_header *) list;
return header_p->list_length;
} /* linked_list_get_length */
@@ -1,31 +0,0 @@
/* Copyright 2014-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 LINKED_LIST_H
#define LINKED_LIST_H
#include "jrt.h"
typedef uint8_t *linked_list;
#define null_list NULL
linked_list linked_list_init (size_t);
void linked_list_free (linked_list);
void *linked_list_element (linked_list, size_t);
void linked_list_set_element (linked_list, size_t, void *);
void linked_list_remove_element (linked_list, size_t);
uint16_t linked_list_get_length (linked_list);
#endif /* LINKED_LIST_H */
@@ -1,355 +0,0 @@
/* Copyright 2014-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-id-hash-table.h"
#include "bytecode-data.h"
/** \addtogroup jsparser ECMAScript parser
* @{
*
* \addtogroup collections Collections
* @{
*
* \addtogroup lit_id_hash_table Literal identifiers hash table
* The hash table connects pairs (instruction block, vm_idx_t value) with literal identifiers.
* @{
*/
/**
* Initialize literal identifiers hash table
*
* @return pointer to header of the table
*/
lit_id_hash_table *
lit_id_hash_table_init (uint8_t *table_buffer_p, /**< buffer to initialize hash table in */
size_t buffer_size, /**< size of the buffer */
size_t buckets_count, /**< number of pairs */
size_t blocks_count) /**< number of instruction blocks */
{
const size_t header_size = JERRY_ALIGNUP (sizeof (lit_id_hash_table), MEM_ALIGNMENT);
const size_t raw_buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t) * buckets_count, MEM_ALIGNMENT);
const size_t buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t*) * blocks_count, MEM_ALIGNMENT);
JERRY_ASSERT (header_size + raw_buckets_size + buckets_size <= buffer_size);
lit_id_hash_table *table_p = (lit_id_hash_table *) table_buffer_p;
table_p->current_bucket_pos = 0;
table_p->raw_buckets = (lit_cpointer_t*) (table_buffer_p + header_size);
table_p->buckets = (lit_cpointer_t **) (table_buffer_p + header_size + raw_buckets_size);
memset (table_p->buckets, 0, buckets_size);
return table_p;
} /* lit_id_hash_table_init */
/**
* Get size of buffer, necessary to hold hash table with specified parameters
*
* @return size of buffer
*/
size_t
lit_id_hash_table_get_size_for_table (size_t buckets_count, /**< number of pairs */
size_t blocks_count) /**< number of instructions blocks */
{
const size_t header_size = JERRY_ALIGNUP (sizeof (lit_id_hash_table), MEM_ALIGNMENT);
const size_t raw_buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t) * buckets_count, MEM_ALIGNMENT);
const size_t buckets_size = JERRY_ALIGNUP (sizeof (lit_cpointer_t*) * blocks_count, MEM_ALIGNMENT);
return header_size + raw_buckets_size + buckets_size;
} /* lit_id_hash_table_get_size_for_table */
/**
* Free literal identifiers hash table
*/
void
lit_id_hash_table_free (lit_id_hash_table *table_p) /**< table's header */
{
JERRY_ASSERT (table_p != NULL);
mem_heap_free_block ((uint8_t *) table_p);
} /* lit_id_hash_table_free */
/**
* Register literal in the hash table
*
* @return corresponding idx
*/
vm_idx_t
lit_id_hash_table_insert (lit_id_hash_table *table_p, /**< table's header */
vm_instr_counter_t oc, /**< instruction counter of the instruction */
lit_cpointer_t lit_cp) /**< literal identifier */
{
JERRY_ASSERT (table_p != NULL);
size_t block_id = oc / BLOCK_SIZE;
if (table_p->buckets[block_id] == NULL)
{
table_p->buckets[block_id] = table_p->raw_buckets + table_p->current_bucket_pos;
}
lit_cpointer_t *raw_bucket_iter_p = table_p->raw_buckets + table_p->current_bucket_pos;
JERRY_ASSERT (raw_bucket_iter_p >= table_p->buckets[block_id]);
ssize_t bucket_size = (raw_bucket_iter_p - table_p->buckets[block_id]);
int32_t index;
for (index = 0; index < bucket_size; index++)
{
if (table_p->buckets[block_id][index].packed_value == lit_cp.packed_value)
{
break;
}
}
if (index == bucket_size)
{
JERRY_ASSERT ((uint8_t *) (table_p->raw_buckets + table_p->current_bucket_pos) < (uint8_t *) (table_p->buckets));
table_p->buckets[block_id][index] = lit_cp;
table_p->current_bucket_pos++;
}
JERRY_ASSERT (index <= VM_IDX_LITERAL_LAST);
return (vm_idx_t) index;
} /* lit_id_hash_table_insert */
/**
* Lookup literal identifier by pair
*
* @return literal identifier
*/
lit_cpointer_t
lit_id_hash_table_lookup (lit_id_hash_table *table_p, /**< table's header */
vm_idx_t uid, /**< value of byte-code instruction's argument */
vm_instr_counter_t oc) /**< instruction counter of the instruction */
{
JERRY_ASSERT (table_p != NULL);
size_t block_id = oc / BLOCK_SIZE;
JERRY_ASSERT (table_p->buckets[block_id] != NULL);
return table_p->buckets[block_id][uid];
} /* lit_id_hash_table_lookup */
/**
* Dump literal identifiers hash table to snapshot buffer
*
* @return number of bytes dumper - upon success,
* 0 - upon failure
*/
uint32_t
lit_id_hash_table_dump_for_snapshot (uint8_t *buffer_p, /**< buffer to dump to */
size_t buffer_size, /**< buffer size */
size_t *in_out_buffer_offset_p, /**< in-out: buffer write offset */
lit_id_hash_table *table_p, /**< hash table to dump */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map from literal
* identifiers in
* literal storage
* to literal offsets
* in snapshot */
uint32_t literals_num, /**< number of literals */
vm_instr_counter_t instrs_num) /**< number of instructions in corresponding
* byte-code array */
{
size_t begin_offset = *in_out_buffer_offset_p;
uint32_t idx_num_total = (uint32_t) table_p->current_bucket_pos;
JERRY_ASSERT (idx_num_total == table_p->current_bucket_pos);
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
in_out_buffer_offset_p,
&idx_num_total,
sizeof (idx_num_total)))
{
return 0;
}
size_t blocks_num = JERRY_ALIGNUP (instrs_num, BLOCK_SIZE) / BLOCK_SIZE;
for (size_t block_index = 0, next_block_index;
block_index < blocks_num;
)
{
uint32_t idx_num_in_block;
next_block_index = block_index + 1u;
while (next_block_index < blocks_num
&& table_p->buckets[next_block_index] == NULL)
{
next_block_index++;
}
if (next_block_index != blocks_num)
{
idx_num_in_block = (uint32_t) (table_p->buckets[next_block_index] - table_p->buckets[block_index]);
}
else if (table_p->buckets[block_index] != NULL)
{
idx_num_in_block = (uint32_t) (table_p->current_bucket_pos
- (size_t) (table_p->buckets[block_index] - table_p->buckets[0]));
}
else
{
idx_num_in_block = 0;
}
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
in_out_buffer_offset_p,
&idx_num_in_block,
sizeof (idx_num_in_block)))
{
return 0;
}
for (size_t block_idx_pair_index = 0;
block_idx_pair_index < idx_num_in_block;
block_idx_pair_index++)
{
lit_cpointer_t lit_cp = table_p->buckets[block_index][block_idx_pair_index];
uint32_t offset = bc_find_lit_offset (lit_cp, lit_map_p, literals_num);
if (!jrt_write_to_buffer_by_offset (buffer_p, buffer_size, in_out_buffer_offset_p, &offset, sizeof (offset)))
{
return 0;
}
}
while (++block_index < next_block_index)
{
idx_num_in_block = 0;
if (!jrt_write_to_buffer_by_offset (buffer_p,
buffer_size,
in_out_buffer_offset_p,
&idx_num_in_block,
sizeof (idx_num_in_block)))
{
return 0;
}
}
}
size_t bytes_written = (*in_out_buffer_offset_p - begin_offset);
JERRY_ASSERT (bytes_written == (uint32_t) bytes_written);
return (uint32_t) bytes_written;
} /* lit_id_hash_table_dump_for_snapshot */
/**
* Load literal identifiers hash table from specified snapshot buffer
*
* @return true - upon successful load (i.e. data in snapshot is consistent),
* false - upon failure (in case, snapshot is incorrect)
*/
bool
lit_id_hash_table_load_from_snapshot (size_t blocks_count, /**< number of byte-code blocks
* in corresponding byte-code array */
uint32_t idx_num_total, /**< total number of (byte-code block, idx)
* pairs in snapshot */
const uint8_t *idx_to_lit_map_p, /**< idx-to-lit map in snapshot */
size_t idx_to_lit_map_size, /**< size of the map */
const lit_mem_to_snapshot_id_map_entry_t *lit_map_p, /**< map of in-snapshot
* literal offsets
* to literal identifiers,
* created in literal
* storage */
uint32_t literals_num, /**< number of literals in snapshot */
uint8_t *buffer_for_hash_table_p, /**< buffer to initialize hash table in */
size_t buffer_for_hash_table_size) /**< size of the buffer */
{
lit_id_hash_table *hash_table_p = lit_id_hash_table_init (buffer_for_hash_table_p,
buffer_for_hash_table_size,
idx_num_total,
blocks_count);
size_t idx_to_lit_map_offset = 0;
uint32_t idx_num_counter = 0;
for (size_t block_idx = 0; block_idx < blocks_count; block_idx++)
{
uint32_t idx_num_in_block;
if (!jrt_read_from_buffer_by_offset (idx_to_lit_map_p,
idx_to_lit_map_size,
&idx_to_lit_map_offset,
&idx_num_in_block,
sizeof (idx_num_in_block)))
{
return false;
}
hash_table_p->buckets[block_idx] = hash_table_p->raw_buckets + hash_table_p->current_bucket_pos;
if (idx_num_counter + idx_num_in_block < idx_num_counter)
{
return false;
}
idx_num_counter += idx_num_in_block;
if (idx_num_counter > idx_num_total)
{
return false;
}
for (uint32_t idx_in_block = 0; idx_in_block < idx_num_in_block; idx_in_block++)
{
uint32_t lit_offset_from_snapshot;
if (!jrt_read_from_buffer_by_offset (idx_to_lit_map_p,
idx_to_lit_map_size,
&idx_to_lit_map_offset,
&lit_offset_from_snapshot,
sizeof (lit_offset_from_snapshot)))
{
return false;
}
/**
* TODO: implement binary search here
*/
lit_cpointer_t lit_cp = rcs_cpointer_null_cp ();
uint32_t i;
for (i = 0; i < literals_num; i++)
{
if (lit_map_p[i].literal_offset == lit_offset_from_snapshot)
{
lit_cp.packed_value = lit_map_p[i].literal_id.packed_value;
break;
}
}
if (i == literals_num)
{
return false;
}
JERRY_ASSERT (hash_table_p->current_bucket_pos < idx_num_total);
hash_table_p->raw_buckets[hash_table_p->current_bucket_pos++] = lit_cp;
}
}
return true;
} /* lit_id_hash_table_load_from_snapshot */
/**
* @}
* @}
* @}
*/
@@ -1,41 +0,0 @@
/* Copyright 2014-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_ID_HASH_TABLE
#define LIT_ID_HASH_TABLE
#include "jrt.h"
#include "ecma-globals.h"
#include "opcodes.h"
#include "lit-literal.h"
#include "lit-snapshot.h"
typedef struct
{
size_t current_bucket_pos;
lit_cpointer_t *raw_buckets;
lit_cpointer_t **buckets;
} lit_id_hash_table;
lit_id_hash_table *lit_id_hash_table_init (uint8_t *, size_t, size_t, size_t);
size_t lit_id_hash_table_get_size_for_table (size_t, size_t);
void lit_id_hash_table_free (lit_id_hash_table *);
vm_idx_t lit_id_hash_table_insert (lit_id_hash_table *,vm_instr_counter_t, lit_cpointer_t);
lit_cpointer_t lit_id_hash_table_lookup (lit_id_hash_table *, vm_idx_t, vm_instr_counter_t);
uint32_t lit_id_hash_table_dump_for_snapshot (uint8_t *, size_t, size_t *, lit_id_hash_table *,
const lit_mem_to_snapshot_id_map_entry_t *, uint32_t, vm_instr_counter_t);
bool lit_id_hash_table_load_from_snapshot (size_t, uint32_t, const uint8_t *, size_t,
const lit_mem_to_snapshot_id_map_entry_t *, uint32_t, uint8_t *, size_t);
#endif /* LIT_ID_HASH_TABLE */
-216
View File
@@ -1,216 +0,0 @@
/* Copyright 2014-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.
*/
/**
This file contains macros to define and use stacks.
Use macro STACK or STATIC_STACK to create stack variable and define all necessaty routines.
Also, define variable with name NAME##_global_size. If the variable more than 0,
first NAME##_global_size element will remain untouched during STACK_PUSH and STACK_POP operations.
Before using the stack, init it by calling STACK_INIT macro.
Use macros STACK_PUSH, STACK_POP, STACK_DROP, STACK_CLEAN and STACK_HEAD to manipulate the stack.
DO NOT FORGET to free stack memory by calling STACK_FREE macro.
For check usage of stack during a function, use STACK_DECLARE_USAGE and STACK_CHECK_USAGE macros.
For the purpose of memory fragmentation reduction, the memory is allocated by chunks and them are
used to store data. The chunks are connected to each other in manner of double-linked list.
Macro STACK_CONVERT_TO_RAW_DATA allocates memory, so use it after finishing working with the stack.
Example (parser.c):
enum
{
temp_name,
min_temp_name,
max_temp_name,
temp_names_global_size
};
STACK (temp_names, uint8_t, uint8_t)
#define GLOBAL(NAME, VAR) \
STACK_ELEMENT (NAME, VAR)
#define MAX_TEMP_NAME() \
GLOBAL (temp_names, max_temp_name)
#define MIN_TEMP_NAME() \
GLOBAL (temp_names, min_temp_name)
#define TEMP_NAME() \
GLOBAL (temp_names, temp_name)
void
parser_init (void)
{
STACK_INIT (temp_names)
}
void
parser_free (void)
{
STACK_FREE (temp_names)
}
*/
#ifndef STACK_H
#define STACK_H
#include "array-list.h"
#define DEFINE_STACK_TYPE(NAME, TYPE) \
typedef TYPE NAME##_stack_value_type; \
typedef struct \
{ \
array_list data; \
} \
NAME##_stack;
#define STACK_INIT(NAME) \
do { \
NAME.data = array_list_init (sizeof (NAME##_stack_value_type)); \
} while (0)
#define STACK_FREE(NAME) \
do { \
array_list_free (NAME.data); \
NAME.data = null_list; \
} while (0)
#define DEFINE_STACK_ELEMENT(NAME, TYPE) \
static TYPE NAME##_stack_element (size_t) __attr_unused___; \
static TYPE NAME##_stack_element (size_t elem) { \
return *((TYPE *) array_list_element (NAME.data, elem)); \
}
#define DEFINE_SET_STACK_ELEMENT(NAME, TYPE) \
static void set_##NAME##_stack_element (size_t, TYPE) __attr_unused___; \
static void set_##NAME##_stack_element (size_t elem, TYPE value) { \
array_list_set_element (NAME.data, elem, &value); \
}
#define DEFINE_STACK_HEAD(NAME, TYPE) \
static TYPE NAME##_stack_head (size_t) __attr_unused___; \
static TYPE NAME##_stack_head (size_t elem) { \
return *((TYPE *) array_list_last_element (NAME.data, elem)); \
}
#define DEFINE_SET_STACK_HEAD(NAME, TYPE) \
static void set_##NAME##_stack_head (size_t, TYPE) __attr_unused___; \
static void set_##NAME##_stack_head (size_t elem, TYPE value) { \
array_list_set_last_element (NAME.data, elem, &value); \
}
#define DEFINE_STACK_PUSH(NAME, TYPE) \
static void NAME##_stack_push (TYPE) __attr_unused___; \
static void NAME##_stack_push (TYPE value) { \
NAME.data = array_list_append (NAME.data, &value); \
}
#define STACK_PUSH(NAME, VALUE) \
do { NAME##_stack_push (VALUE); } while (0)
#define STACK_DROP(NAME, I) \
do { \
for (size_t i = 0, till = (size_t) (I); i < till; i++) { \
array_list_drop_last (NAME.data); } } while (0)
#define STACK_CLEAN(NAME) \
STACK_DROP (NAME, NAME.current - NAME##_global_size);
#define STACK_HEAD(NAME, I) \
NAME##_stack_head ((size_t) (I))
#define STACK_SET_HEAD(NAME, I, VALUE) \
do { set_##NAME##_stack_head ((size_t) (I), VALUE); } while (0)
#define STACK_INCR_HEAD(NAME, I) \
do { STACK_SET_HEAD (NAME, I, (NAME##_stack_value_type) (STACK_HEAD (NAME, I) + 1)); } while (0)
#define STACK_DECR_HEAD(NAME, I) \
do { STACK_SET_HEAD (NAME, I, (NAME##_stack_value_type) (STACK_HEAD (NAME, I) - 1)); } while (0)
#define STACK_TOP(NAME) \
STACK_HEAD (NAME, 1)
#define STACK_SWAP(NAME) \
do { \
NAME##_stack_value_type temp = STACK_TOP (NAME); \
STACK_SET_HEAD (NAME, 1, STACK_HEAD (NAME, 2)); \
STACK_SET_HEAD (NAME, 2, temp); \
} while (0)
#define STACK_SIZE(NAME) \
array_list_len (NAME.data)
#define STACK_ELEMENT(NAME, I) \
NAME##_stack_element ((size_t) (I))
#define STACK_SET_ELEMENT(NAME, I, VALUE) \
do { set_##NAME##_stack_element ((size_t) I, VALUE); } while (0)
#define STACK_CONVERT_TO_RAW_DATA(NAME, DATA) \
do { DATA = convert_##NAME##_to_raw_data (); } while (0)
#define STACK_INCR_ELEMENT(NAME, I) \
do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT (NAME, I) + 1)); } while (0)
#define STACK_DECR_ELEMENT(NAME, I) \
do { STACK_SET_ELEMENT (NAME, I, (NAME##_stack_value_type) (STACK_ELEMENT (NAME, I) - 1)); } while (0)
#define STACK_ITERATE(NAME, VAL, FROM) \
for (size_t NAME##_i = FROM; \
NAME##_i < array_list_len (NAME.data); \
NAME##_i++) \
{ \
NAME##_stack_value_type VAL = STACK_ELEMENT (NAME, NAME##_i);
#define STACK_ITERATE_END() \
}
#define STACK_ITERATE_VARG_SET(NAME, FUNC, FROM, ...) \
do { for (size_t i = FROM; i < array_list_len (NAME.data); i++) { \
STACK_SET_ELEMENT (NAME, i, FUNC (STACK_ELEMENT (NAME, i), __VA_ARGS__)); \
} } while (0)
#define STACK(NAME, TYPE) \
DEFINE_STACK_TYPE (NAME, TYPE) \
NAME##_stack NAME; \
DEFINE_STACK_ELEMENT (NAME, TYPE) \
DEFINE_SET_STACK_ELEMENT (NAME, TYPE) \
DEFINE_STACK_HEAD (NAME, TYPE) \
DEFINE_SET_STACK_HEAD (NAME, TYPE) \
DEFINE_STACK_PUSH (NAME, TYPE)
#define STATIC_STACK(NAME, TYPE) \
DEFINE_STACK_TYPE (NAME, TYPE) \
static NAME##_stack NAME; \
DEFINE_STACK_ELEMENT (NAME, TYPE) \
DEFINE_SET_STACK_ELEMENT (NAME, TYPE) \
DEFINE_STACK_HEAD (NAME, TYPE) \
DEFINE_SET_STACK_HEAD (NAME, TYPE) \
DEFINE_STACK_PUSH (NAME, TYPE)
#ifndef JERRY_NDEBUG
#define STACK_DECLARE_USAGE(NAME) \
size_t NAME##_current = array_list_len (NAME.data);
#define STACK_CHECK_USAGE(NAME) \
do { \
JERRY_ASSERT (array_list_len (NAME.data) == NAME##_current); \
} while (0)
#else
#define STACK_DECLARE_USAGE(NAME) ;
#define STACK_CHECK_USAGE(NAME) ;
#endif /* JERRY_NDEBUG */
#endif /* STACK_H */
+262
View File
@@ -0,0 +1,262 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 "common.h"
#include "ecma-helpers.h"
#include "lit-char-helpers.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_utils Utility
* @{
*/
/**
* Checks whether the next UTF8 character is a valid identifier start.
*
* @return non-zero if it is.
*/
int
util_is_identifier_start (const uint8_t *src_p) /* pointer to a vaild UTF8 character */
{
if (*src_p <= 127)
{
return util_is_identifier_start_character (*src_p);
}
return util_is_identifier_start_character (lit_utf8_peek_next (src_p));
} /* util_is_identifier_start */
/**
* Checks whether the next UTF8 character is a valid identifier part.
*
* @return non-zero if it is.
*/
int
util_is_identifier_part (const uint8_t *src_p) /* pointer to a vaild UTF8 character */
{
if (*src_p <= 127)
{
return util_is_identifier_part_character (*src_p);
}
return util_is_identifier_part_character (lit_utf8_peek_next (src_p));
} /* util_is_identifier_part */
/**
* Checks whether the character is a valid identifier start.
*
* @return non-zero if it is.
*/
int
util_is_identifier_start_character (uint16_t chr) /**< EcmaScript character */
{
if (chr <= 127)
{
return (((chr | 0x20) >= LIT_CHAR_LOWERCASE_A && (chr | 0x20) <= LIT_CHAR_LOWERCASE_Z)
|| chr == LIT_CHAR_DOLLAR_SIGN
|| chr == LIT_CHAR_UNDERSCORE);
}
return lit_char_is_unicode_letter (chr);
} /* util_is_identifier_start_character */
/**
* Checks whether the character is a valid identifier part.
*
* @return non-zero if it is.
*/
int
util_is_identifier_part_character (uint16_t chr) /**< EcmaScript character */
{
if (chr <= 127)
{
return (((chr | 0x20) >= LIT_CHAR_LOWERCASE_A && (chr | 0x20) <= LIT_CHAR_LOWERCASE_Z)
|| (chr >= LIT_CHAR_0 && chr <= LIT_CHAR_9)
|| chr == LIT_CHAR_DOLLAR_SIGN
|| chr == LIT_CHAR_UNDERSCORE);
}
return (lit_char_is_unicode_letter (chr)
|| lit_char_is_unicode_combining_mark (chr)
|| lit_char_is_unicode_digit (chr)
|| lit_char_is_unicode_connector_punctuation (chr));
} /* util_is_identifier_part_character */
/**
* Converts a character to UTF8 bytes.
*
* @return length of the UTF8 representation.
*/
size_t
util_to_utf8_bytes (uint8_t *dst_p, /**< destination buffer */
uint16_t chr) /**< EcmaScript character */
{
if (!(chr & ~0x007f))
{
/* 00000000 0xxxxxxx -> 0xxxxxxx */
*dst_p = (uint8_t) chr;
return 1;
}
if (!(chr & ~0x07ff))
{
/* 00000yyy yyxxxxxx -> 110yyyyy 10xxxxxx */
*(dst_p++) = (uint8_t) (0xc0 | ((chr >> 6) & 0x1f));
*dst_p = (uint8_t) (0x80 | (chr & 0x3f));
return 2;
}
/* zzzzyyyy yyxxxxxx -> 1110zzzz 10yyyyyy 10xxxxxx */
*(dst_p++) = (uint8_t) (0xe0 | ((chr >> 12) & 0x0f));
*(dst_p++) = (uint8_t) (0x80 | ((chr >> 6) & 0x3f));
*dst_p = (uint8_t) (0x80 | (chr & 0x3f));
return 3;
} /* util_to_utf8_bytes */
/**
* Returns the length of the UTF8 representation of a character.
*
* @return length of the UTF8 representation.
*/
size_t
util_get_utf8_length (uint16_t chr) /**< EcmaScript character */
{
if (!(chr & ~0x007f))
{
/* 00000000 0xxxxxxx */
return 1;
}
if (!(chr & ~0x07ff))
{
/* 00000yyy yyxxxxxx */
return 2;
}
/* zzzzyyyy yyxxxxxx */
return 3;
} /* util_get_utf8_length */
/**
* Free literal.
*/
void
util_free_literal (lexer_literal_t *literal_p) /**< literal */
{
if (literal_p->type == LEXER_IDENT_LITERAL
|| literal_p->type == LEXER_STRING_LITERAL)
{
if (!(literal_p->status_flags & LEXER_FLAG_SOURCE_PTR))
{
PARSER_FREE ((uint8_t *) literal_p->u.char_p);
}
}
else if ((literal_p->type == LEXER_FUNCTION_LITERAL)
|| (literal_p->type == LEXER_REGEXP_LITERAL))
{
ecma_bytecode_deref (literal_p->u.bytecode_p);
}
} /* util_free_literal */
#ifdef PARSER_DUMP_BYTE_CODE
/**
* Debug utility to print a character sequence.
*/
static void
util_print_chars (const uint8_t *char_p, /**< character pointer */
size_t size) /**< size */
{
while (size > 0)
{
printf ("%c", *char_p++);
size--;
}
} /* util_print_chars */
/**
* Debug utility to print a number.
*/
static void
util_print_number (ecma_number_t num_p) /**< number to print */
{
lit_utf8_byte_t str_buf[ECMA_MAX_CHARS_IN_STRINGIFIED_NUMBER];
lit_utf8_size_t str_size = ecma_number_to_utf8_string (num_p, str_buf, sizeof (str_buf));
str_buf[str_size] = 0;
printf ("%s", str_buf);
} /* util_print_number */
/**
* Print literal.
*/
void
util_print_literal (lexer_literal_t *literal_p) /**< literal */
{
if (literal_p->type == LEXER_IDENT_LITERAL)
{
if (literal_p->status_flags & LEXER_FLAG_VAR)
{
printf ("var_ident(");
}
else
{
printf ("ident(");
}
util_print_chars (literal_p->u.char_p, literal_p->prop.length);
}
else if (literal_p->type == LEXER_FUNCTION_LITERAL)
{
printf ("function");
return;
}
else if (literal_p->type == LEXER_STRING_LITERAL)
{
printf ("string(");
util_print_chars (literal_p->u.char_p, literal_p->prop.length);
}
else if (literal_p->type == LEXER_NUMBER_LITERAL)
{
lit_literal_t literal = lit_get_literal_by_cp (literal_p->u.value);
printf ("number(");
util_print_number (lit_number_literal_get_number (literal));
}
else if (literal_p->type == LEXER_REGEXP_LITERAL)
{
printf ("regexp");
return;
}
else
{
printf ("unknown");
return;
}
printf (")");
} /* util_print_literal */
#endif /* PARSER_DUMP_BYTE_CODE */
/**
* @}
* @}
* @}
*/
+167
View File
@@ -0,0 +1,167 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 COMMON_H
#define COMMON_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <setjmp.h>
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_utils Utility
* @{
*/
#ifndef JERRY_NDEBUG
#define PARSER_DEBUG
#endif
#ifndef JERRY_NDEBUG
/* Note: This flag is independent from debug mode. */
#define PARSER_DUMP_BYTE_CODE
#endif
#include "ecma-globals.h"
#include "ecma-regexp-object.h"
#include "lit-literal.h"
#include "mem-heap.h"
/* The utilites here are just for compiling purposes, JS
* engines should have an optimized version for them. */
/* Malloc functions. */
#define PARSER_MALLOC(size) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM)
#define PARSER_FREE(ptr) mem_heap_free_block ((void *) ptr)
#define PARSER_MALLOC_LOCAL(size) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_SHORT_TERM)
#define PARSER_FREE_LOCAL(ptr) mem_heap_free_block (ptr)
/* UTF character management. Only ASCII characters are
* supported for simplicity. */
int util_is_identifier_start (const uint8_t *);
int util_is_identifier_part (const uint8_t *);
int util_is_identifier_start_character (uint16_t);
int util_is_identifier_part_character (uint16_t);
size_t util_to_utf8_bytes (uint8_t *, uint16_t);
size_t util_get_utf8_length (uint16_t);
/* Immediate management. */
/**
* Literal types.
*
* The LEXER_UNUSED_LITERAL type is internal and
* used for various purposes.
*/
typedef enum
{
LEXER_IDENT_LITERAL = 0, /**< identifier literal */
LEXER_STRING_LITERAL = 1, /**< string literal */
LEXER_NUMBER_LITERAL = 2, /**< number literal */
LEXER_FUNCTION_LITERAL = 3, /**< function literal */
LEXER_REGEXP_LITERAL = 4, /**< regexp literal */
LEXER_UNUSED_LITERAL = 5, /**< unused literal, can only be
used by the byte code generator. */
} lexer_literal_type_t;
/* Flags for status_flags. */
/* Local identifier (var, function arg). */
#define LEXER_FLAG_VAR 0x01
/* This local identifier cannot be stored in register. */
#define LEXER_FLAG_NO_REG_STORE 0x02
/* This local identifier is initialized with a value. */
#define LEXER_FLAG_INITIALIZED 0x04
/* This local identifier has a reference to the function itself. */
#define LEXER_FLAG_FUNCTION_NAME 0x08
/* This local identifier is a function argument. */
#define LEXER_FLAG_FUNCTION_ARGUMENT 0x10
/* No space is allocated for this character literal. */
#define LEXER_FLAG_SOURCE_PTR 0x20
/* Initialize this variable after the byte code is freed. */
#define LEXER_FLAG_LATE_INIT 0x40
/**
* Literal data.
*/
typedef struct
{
union
{
lit_cpointer_t value; /**< literal value (not processed by the parser) */
const uint8_t *char_p; /**< character value */
ecma_compiled_code_t *bytecode_p; /**< compiled function or regexp pointer */
uint32_t source_data; /**< encoded source literal */
} u;
#ifdef PARSER_DUMP_BYTE_CODE
struct
#else
union
#endif
{
uint16_t length; /**< length of ident / string literal */
uint16_t index; /**< real index during post processing */
} prop;
uint8_t type; /**< type of the literal */
uint8_t status_flags; /**< status flags */
} lexer_literal_t;
void util_free_literal (lexer_literal_t *);
#ifdef PARSER_DUMP_BYTE_CODE
void util_print_literal (lexer_literal_t *);
#endif /* PARSER_DUMP_BYTE_CODE */
/* TRY/CATCH block */
#define PARSER_TRY_CONTEXT(context_name) \
jmp_buf context_name
#define PARSER_THROW(context_name) \
longjmp (context_name, 1);
#define PARSER_TRY(context_name) \
{ \
if (!setjmp (context_name)) \
{ \
#define PARSER_CATCH \
} \
else \
{
#define PARSER_TRY_END \
} \
}
/* Other */
#define PARSER_INLINE inline
#define PARSER_NOINLINE __attribute__ ((noinline))
#endif /* !COMMON_H */
File diff suppressed because it is too large Load Diff
+270
View File
@@ -0,0 +1,270 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 JS_LEXER_H
#define JS_LEXER_H
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_lexer Lexer
* @{
*/
/**
* Lexer token types.
*/
typedef enum
{
LEXER_EOS, /**< end of source */
/* Primary expressions */
LEXER_LITERAL, /**< literal token */
LEXER_KEYW_THIS, /**< this */
LEXER_LIT_TRUE, /**< true (not a keyword!) */
LEXER_LIT_FALSE, /**< false (not a keyword!) */
LEXER_LIT_NULL, /**< null (not a keyword!) */
/* Unary operators
* IMPORTANT: update CBC_UNARY_OP_TOKEN_TO_OPCODE and
* CBC_UNARY_LVALUE_OP_TOKEN_TO_OPCODE after changes. */
#define LEXER_IS_UNARY_OP_TOKEN(token_type) \
((token_type) >= LEXER_PLUS && (token_type) <= LEXER_DECREASE)
#define LEXER_IS_UNARY_LVALUE_OP_TOKEN(token_type) \
((token_type) >= LEXER_KEYW_DELETE && (token_type) <= LEXER_DECREASE)
LEXER_PLUS, /**< + */
LEXER_NEGATE, /**< - */
LEXER_LOGICAL_NOT, /**< ! */
LEXER_BIT_NOT, /**< ~ */
LEXER_KEYW_VOID, /**< void */
LEXER_KEYW_TYPEOF, /**< typeof */
LEXER_KEYW_DELETE, /**< delete */
LEXER_INCREASE, /**< ++ */
LEXER_DECREASE, /**< -- */
/* Binary operators
* IMPORTANT: update CBC_BINARY_OP_TOKEN_TO_OPCODE,
* CBC_BINARY_LVALUE_OP_TOKEN_TO_OPCODE and
* parser_binary_precedence_table after changes. */
#define LEXER_IS_BINARY_OP_TOKEN(token_type) \
((token_type) >= LEXER_ASSIGN && (token_type) <= LEXER_MODULO)
#define LEXER_IS_BINARY_LVALUE_TOKEN(token_type) \
((token_type) >= LEXER_ASSIGN && (token_type) <= LEXER_ASSIGN_BIT_XOR)
#define LEXER_FIRST_BINARY_OP LEXER_ASSIGN
LEXER_ASSIGN, /**< = (prec: 3) */
LEXER_ASSIGN_ADD, /**< += (prec: 3) */
LEXER_ASSIGN_SUBTRACT, /**< -= (prec: 3) */
LEXER_ASSIGN_MULTIPLY, /**< *= (prec: 3) */
LEXER_ASSIGN_DIVIDE, /**< /= (prec: 3) */
LEXER_ASSIGN_MODULO, /**< %= (prec: 3) */
LEXER_ASSIGN_LEFT_SHIFT, /**< <<= (prec: 3) */
LEXER_ASSIGN_RIGHT_SHIFT, /**< >>= (prec: 3) */
LEXER_ASSIGN_UNS_RIGHT_SHIFT, /**< >>>= (prec: 3) */
LEXER_ASSIGN_BIT_AND, /**< &= (prec: 3) */
LEXER_ASSIGN_BIT_OR, /**< |= (prec: 3) */
LEXER_ASSIGN_BIT_XOR, /**< ^= (prec: 3) */
LEXER_QUESTION_MARK, /**< ? (prec: 4) */
LEXER_LOGICAL_OR, /**< || (prec: 5) */
LEXER_LOGICAL_AND, /**< && (prec: 6) */
LEXER_BIT_OR, /**< | (prec: 7) */
LEXER_BIT_XOR, /**< ^ (prec: 8) */
LEXER_BIT_AND, /**< & (prec: 9) */
LEXER_EQUAL, /**< == (prec: 10) */
LEXER_NOT_EQUAL, /**< != (prec: 10) */
LEXER_STRICT_EQUAL, /**< === (prec: 10) */
LEXER_STRICT_NOT_EQUAL, /**< !== (prec: 10) */
LEXER_LESS, /**< < (prec: 11) */
LEXER_GREATER, /**< > (prec: 11) */
LEXER_LESS_EQUAL, /**< <= (prec: 11) */
LEXER_GREATER_EQUAL, /**< >= (prec: 11) */
LEXER_KEYW_IN, /**< in (prec: 11) */
LEXER_KEYW_INSTANCEOF, /**< instanceof (prec: 11) */
LEXER_LEFT_SHIFT, /**< << (prec: 12) */
LEXER_RIGHT_SHIFT, /**< >> (prec: 12) */
LEXER_UNS_RIGHT_SHIFT, /**< >>> (prec: 12) */
LEXER_ADD, /**< + (prec: 13) */
LEXER_SUBTRACT, /**< - (prec: 13) */
LEXER_MULTIPLY, /**< * (prec: 14) */
LEXER_DIVIDE, /**< / (prec: 14) */
LEXER_MODULO, /**< % (prec: 14) */
LEXER_LEFT_BRACE, /**< { */
LEXER_LEFT_PAREN, /**< ( */
LEXER_LEFT_SQUARE, /**< [ */
LEXER_RIGHT_BRACE, /**< } */
LEXER_RIGHT_PAREN, /**<_) */
LEXER_RIGHT_SQUARE, /**< ] */
LEXER_DOT, /**< . */
LEXER_SEMICOLON, /**< ; */
LEXER_COLON, /**< : */
LEXER_COMMA, /**< , */
LEXER_KEYW_BREAK, /**< break */
LEXER_KEYW_DO, /**< do */
LEXER_KEYW_CASE, /**< case */
LEXER_KEYW_ELSE, /**< else */
LEXER_KEYW_NEW, /**< new */
LEXER_KEYW_VAR, /**< var */
LEXER_KEYW_CATCH, /**< catch */
LEXER_KEYW_FINALLY, /**< finally */
LEXER_KEYW_RETURN, /**< return */
LEXER_KEYW_CONTINUE, /**< continue */
LEXER_KEYW_FOR, /**< for */
LEXER_KEYW_SWITCH, /**< switch */
LEXER_KEYW_WHILE, /**< while */
LEXER_KEYW_DEBUGGER, /**< debugger */
LEXER_KEYW_FUNCTION, /**< function */
LEXER_KEYW_WITH, /**< with */
LEXER_KEYW_DEFAULT, /**< default */
LEXER_KEYW_IF, /**< if */
LEXER_KEYW_THROW, /**< throw */
LEXER_KEYW_TRY, /**< try */
/* These are virtual tokens. */
LEXER_EXPRESSION_START, /**< expression start */
LEXER_PROPERTY_GETTER, /**< property getter function */
LEXER_PROPERTY_SETTER, /**< property setter function */
LEXER_COMMA_SEP_LIST, /**< comma separated bracketed expression list */
LEXER_SCAN_SWITCH, /**< special value for switch pre-scan */
/* Future reserved words: these keywords
* must form a group after all other keywords. */
#define LEXER_FIRST_FUTURE_RESERVED_WORD LEXER_KEYW_CLASS
LEXER_KEYW_CLASS, /**< class */
LEXER_KEYW_ENUM, /**< enum */
LEXER_KEYW_EXTENDS, /**< extends */
LEXER_KEYW_SUPER, /**< super */
LEXER_KEYW_CONST, /**< const */
LEXER_KEYW_EXPORT, /**< export */
LEXER_KEYW_IMPORT, /**< import */
/* Future strict reserved words: these keywords
* must form a group after future reserved words. */
#define LEXER_FIRST_FUTURE_STRICT_RESERVED_WORD LEXER_KEYW_IMPLEMENTS
LEXER_KEYW_IMPLEMENTS, /**< implements */
LEXER_KEYW_LET, /**< let */
LEXER_KEYW_PRIVATE, /**< private */
LEXER_KEYW_PUBLIC, /**< public */
LEXER_KEYW_YIELD, /**< yield */
LEXER_KEYW_INTERFACE, /**< interface */
LEXER_KEYW_PACKAGE, /**< package */
LEXER_KEYW_PROTECTED, /**< protected */
LEXER_KEYW_STATIC, /**< static */
} lexer_token_type_t;
#define LEXER_NEWLINE_LS_PS_BYTE_1 0xe2
#define LEXER_NEWLINE_LS_PS_BYTE_23(source) ((source)[1] == 0x80 && ((source)[2] | 0x1) == 0xa9)
#define LEXER_UTF8_4BYTE_START 0xf0
#define LEXER_IS_LEFT_BRACKET(type) \
((type) == LEXER_LEFT_BRACE || (type) == LEXER_LEFT_PAREN || (type) == LEXER_LEFT_SQUARE)
#define LEXER_IS_RIGHT_BRACKET(type) \
((type) == LEXER_RIGHT_BRACE || (type) == LEXER_RIGHT_PAREN || (type) == LEXER_RIGHT_SQUARE)
#define LEXER_UNARY_OP_TOKEN_TO_OPCODE(token_type) \
((((token_type) - LEXER_PLUS) * 2) + CBC_PLUS)
#define LEXER_UNARY_LVALUE_OP_TOKEN_TO_OPCODE(token_type) \
((((token_type) - LEXER_KEYW_DELETE) * 6) + CBC_DELETE)
#define LEXER_BINARY_OP_TOKEN_TO_OPCODE(token_type) \
((cbc_opcode_t) ((((token_type) - LEXER_BIT_OR) * 3) + CBC_BIT_OR))
#define LEXER_BINARY_LVALUE_OP_TOKEN_TO_OPCODE(token_type) \
((cbc_opcode_t) ((((token_type) - LEXER_ASSIGN_ADD) * 2) + CBC_ASSIGN_ADD))
#define LEXER_TO_ASCII_LOWERCASE(character) ((character) | 0x20)
/**
* Lexer literal object types.
*/
typedef enum
{
LEXER_LITERAL_OBJECT_ANY, /**< unspecified object type */
LEXER_LITERAL_OBJECT_EVAL, /**< reference is equal to eval */
LEXER_LITERAL_OBJECT_ARGUMENTS, /**< reference is equal to arguments */
} lexer_literal_object_type_t;
/**
* Lexer number types.
*/
typedef enum
{
LEXER_NUMBER_DECIMAL, /**< decimal number */
LEXER_NUMBER_HEXADECIMAL, /**< hexadecimal number */
LEXER_NUMBER_OCTAL, /**< octal number */
} lexer_number_type_t;
/**
* Lexer character (string / identifier) literal data.
*/
typedef struct
{
const uint8_t *char_p; /**< start of identifier or string token */
uint16_t length; /**< length or index of a literal */
uint8_t type; /**< type of the current literal */
uint8_t has_escape; /**< has escape sequences */
} lexer_lit_location_t;
/**
* Range of input string which processing is postponed.
*/
typedef struct
{
const uint8_t *source_p; /**< next source byte */
const uint8_t *source_end_p; /**< last source byte */
parser_line_counter_t line; /**< token start line */
parser_line_counter_t column; /**< token start column */
} lexer_range_t;
/**
* Lexer token.
*/
typedef struct
{
uint8_t type; /**< token type */
uint8_t literal_is_reserved; /**< future reserved keyword
* (when char_literal.type is LEXER_IDENT_LITERAL) */
uint8_t extra_value; /**< helper value for different purposes */
uint8_t was_newline; /**< newline occured before this token */
parser_line_counter_t line; /**< token start line */
parser_line_counter_t column; /**< token start column */
lexer_lit_location_t lit_location; /**< extra data for character literals */
} lexer_token_t;
/**
* Literal data set by lexer_construct_literal_object.
*/
typedef struct
{
lexer_literal_t *literal_p; /**< pointer to the literal object */
uint16_t index; /**< literal index */
uint8_t type; /**< literal object type */
} lexer_lit_object_t;
/**
* @}
* @}
* @}
*/
#endif /* !JS_LEXER_H */
File diff suppressed because it is too large Load Diff
+378
View File
@@ -0,0 +1,378 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 JS_PARSER_INTERNAL_H
#define JS_PARSER_INTERNAL_H
#include "common.h"
#include "js-parser.h"
#include "js-parser-limits.h"
#include "js-lexer.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_internals Internals
* @{
*/
/* General parser flags. */
#define PARSER_IS_STRICT 0x00001u
#define PARSER_IS_FUNCTION 0x00002u
#define PARSER_IS_CLOSURE 0x00004u
#define PARSER_IS_PROPERTY_GETTER 0x00008u
#define PARSER_IS_PROPERTY_SETTER 0x00010u
#define PARSER_IS_FUNC_EXPRESSION 0x00020u
#define PARSER_HAS_NON_STRICT_ARG 0x00040u
#define PARSER_INSIDE_WITH 0x00080u
#define PARSER_RESOLVE_THIS_FOR_CALLS 0x00100u
#define PARSER_NAMED_FUNCTION_EXP 0x00200u
#define PARSER_HAS_INITIALIZED_VARS 0x00400u
#define PARSER_NO_END_LABEL 0x00800u
#define PARSER_NO_REG_STORE 0x01000u
#define PARSER_ARGUMENTS_NEEDED 0x02000u
#define PARSER_ARGUMENTS_NOT_NEEDED 0x04000u
#define PARSER_LEXICAL_ENV_NEEDED 0x08000u
#define PARSER_HAS_LATE_LIT_INIT 0x10000u
/* Expression parsing flags. */
#define PARSE_EXPR 0x00
#define PARSE_EXPR_STATEMENT 0x01
#define PARSE_EXPR_BLOCK 0x02
#define PARSE_EXPR_NO_COMMA 0x04
#define PARSE_EXPR_HAS_LITERAL 0x08
/* The maximum of PARSER_CBC_STREAM_PAGE_SIZE is 127. */
#define PARSER_CBC_STREAM_PAGE_SIZE \
((uint32_t) (64 - sizeof (void*)))
#define PARSER_STACK_PAGE_SIZE \
((uint32_t) (((sizeof (void*) > 4) ? 128 : 64) - sizeof (void*)))
/* Avoid compiler warnings for += operations. */
#define PARSER_PLUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) + (value))
#define PARSER_MINUS_EQUAL_U16(base, value) (base) = (uint16_t) ((base) - (value))
#define PARSER_PLUS_EQUAL_LC(base, value) (base) = (parser_line_counter_t) ((base) + (value))
/**
* Parser boolean type.
*/
typedef enum
{
PARSER_FALSE = 0, /**< false constant */
PARSER_TRUE = 1 /**< true constant */
} parser_boolean_t;
/**
* Argument for a compact-byte code.
*/
typedef struct
{
uint16_t literal_index; /**< literal index argument */
uint16_t value; /**< other argument (second literal or byte). */
uint16_t third_literal_index; /**< literal index argument */
uint8_t literal_type; /**< last literal type */
uint8_t literal_object_type; /**< last literal object type */
} cbc_argument_t;
/* Useful parser macros. */
#define PARSER_CBC_UNAVAILABLE CBC_EXT_OPCODE
#define PARSER_TO_EXT_OPCODE(opcode) ((uint16_t) ((opcode) + 256))
#define PARSER_GET_EXT_OPCODE(opcode) ((opcode) - 256)
#define PARSER_IS_BASIC_OPCODE(opcode) ((opcode) < 256)
#define PARSER_IS_PUSH_LITERAL(opcode) \
((opcode) == CBC_PUSH_LITERAL \
|| (opcode) == CBC_PUSH_TWO_LITERALS \
|| (opcode) == CBC_PUSH_THREE_LITERALS)
#define PARSER_GET_LITERAL(literal_index) \
((lexer_literal_t *) parser_list_get (&context_p->literal_pool, (literal_index)))
#define PARSER_TO_BINARY_OPERATION_WITH_RESULT(opcode) \
(PARSER_TO_EXT_OPCODE(opcode) - CBC_ASSIGN_ADD + CBC_EXT_ASSIGN_ADD_PUSH_RESULT)
#define PARSER_TO_BINARY_OPERATION_WITH_BLOCK(opcode) \
((uint16_t) (PARSER_TO_EXT_OPCODE(opcode) - CBC_ASSIGN_ADD + CBC_EXT_ASSIGN_ADD_BLOCK))
#define PARSER_GET_FLAGS(op) \
(PARSER_IS_BASIC_OPCODE (op) ? cbc_flags[(op)] : cbc_ext_flags[PARSER_GET_EXT_OPCODE (op)])
#define PARSER_OPCODE_IS_RETURN(op) \
((op) == CBC_RETURN || (op) == CBC_RETURN_WITH_BLOCK || (op) == CBC_RETURN_WITH_LITERAL)
#define PARSER_ARGS_EQ(op, types) \
((PARSER_GET_FLAGS (op) & CBC_ARG_TYPES) == (types))
/**
* All data allocated by the parser is
* stored in parser_data_pages in the memory.
*/
typedef struct parser_mem_page_t
{
struct parser_mem_page_t *next_p; /**< next page */
uint8_t bytes[1]; /**< memory bytes */
} parser_mem_page_t;
/**
* Structure for managing parser memory.
*/
typedef struct
{
parser_mem_page_t *first_p; /**< first allocated page */
parser_mem_page_t *last_p; /**< last allocated page */
uint32_t last_position; /**< position of the last allocated byte */
} parser_mem_data_t;
/**
* Parser memory list.
*/
typedef struct
{
parser_mem_data_t data; /**< storage space */
uint32_t page_size; /**< size of each page */
uint32_t item_size; /**< size of each item */
uint32_t item_count; /**< number of items on each page */
} parser_list_t;
/**
* Iterator for parser memory list.
*/
typedef struct
{
parser_list_t *list_p; /**< parser list */
parser_mem_page_t *current_p; /**< currently processed page */
size_t current_position; /**< current position on the page */
} parser_list_iterator_t;
/**
* Parser memory stack.
*/
typedef struct
{
parser_mem_data_t data; /**< storage space */
parser_mem_page_t *free_page_p; /**< space for fast allocation */
} parser_stack_t;
/**
* Iterator for parser memory stack.
*/
typedef struct
{
parser_mem_page_t *current_p; /**< currently processed page */
size_t current_position; /**< current position on the page */
} parser_stack_iterator_t;
/**
* Branch type.
*/
typedef struct
{
parser_mem_page_t *page_p; /**< branch location page */
uint32_t offset; /**< branch location offset */
} parser_branch_t;
/**
* Branch chain type.
*/
typedef struct parser_branch_node_t
{
struct parser_branch_node_t *next_p; /**< next linked list node */
parser_branch_t branch; /**< branch */
} parser_branch_node_t;
/**
* Those members of a context which needs
* to be saved when a sub-function is parsed.
*/
typedef struct parser_saved_context_t
{
/* Parser members. */
uint32_t status_flags; /**< parsing options */
uint16_t stack_depth; /**< current stack depth */
uint16_t stack_limit; /**< maximum stack depth */
struct parser_saved_context_t *prev_context_p; /**< last saved context */
parser_stack_iterator_t last_statement; /**< last statement position */
/* Literal types */
uint16_t argument_count; /**< number of function arguments */
uint16_t register_count; /**< number of registers */
uint16_t literal_count; /**< number of literals */
/* Memory storage members. */
parser_mem_data_t byte_code; /**< byte code buffer */
uint32_t byte_code_size; /**< byte code size for branches */
parser_mem_data_t literal_pool_data; /**< literal list */
#ifdef PARSER_DEBUG
uint16_t context_stack_depth; /**< current context stack depth */
#endif
} parser_saved_context_t;
/**
* Shared parser context.
*/
typedef struct
{
PARSER_TRY_CONTEXT (try_buffer); /**< try_buffer */
parser_error_t error; /**< error code */
void *allocated_buffer_p; /**< dinamically allocated buffer
* which needs to be freed on error */
/* Parser members. */
uint32_t status_flags; /**< status flags */
uint16_t stack_depth; /**< current stack depth */
uint16_t stack_limit; /**< maximum stack depth */
parser_saved_context_t *last_context_p; /**< last saved context */
parser_stack_iterator_t last_statement; /**< last statement position */
/* Lexer members. */
lexer_token_t token; /**< current token */
lexer_lit_object_t lit_object; /**< current literal object */
const uint8_t *source_p; /**< next source byte */
const uint8_t *source_end_p; /**< last source byte */
parser_line_counter_t line; /**< current line */
parser_line_counter_t column; /**< current column */
/* Compact byte code members. */
cbc_argument_t last_cbc; /**< argument of the last cbc */
uint16_t last_cbc_opcode; /**< opcode of the last cbc */
/* Literal types */
uint16_t argument_count; /**< number of function arguments */
uint16_t register_count; /**< number of registers */
uint16_t literal_count; /**< number of literals */
/* Memory storage members. */
parser_mem_data_t byte_code; /**< byte code buffer */
uint32_t byte_code_size; /**< current byte code size for branches */
parser_list_t literal_pool; /**< literal list */
parser_mem_data_t stack; /**< storage space */
parser_mem_page_t *free_page_p; /**< space for fast allocation */
uint8_t stack_top_uint8; /**< top byte stored on the stack */
#ifdef PARSER_DEBUG
/* Variables for debugging / logging. */
uint16_t context_stack_depth; /**< current context stack depth */
#endif /* PARSER_DEBUG */
#ifdef PARSER_DUMP_BYTE_CODE
int is_show_opcodes; /**< show opcodes */
uint32_t total_byte_code_size; /**< total byte code size */
#endif /* PARSER_DUMP_BYTE_CODE */
} parser_context_t;
/* Memory management.
* Note: throws an error if unsuccessful. */
void *parser_malloc (parser_context_t *, size_t);
void parser_free (void *);
void *parser_malloc_local (parser_context_t *, size_t);
void parser_free_local (void *);
/* Parser byte stream. */
void parser_cbc_stream_init (parser_mem_data_t *);
void parser_cbc_stream_free (parser_mem_data_t *);
void parser_cbc_stream_alloc_page (parser_context_t *, parser_mem_data_t *);
/* Parser list. Ensures pointer alignment. */
void parser_list_init (parser_list_t *, uint32_t, uint32_t);
void parser_list_free (parser_list_t *);
void parser_list_reset (parser_list_t *);
void *parser_list_append (parser_context_t *, parser_list_t *);
void *parser_list_get (parser_list_t *, size_t);
void parser_list_iterator_init (parser_list_t *, parser_list_iterator_t *);
void *parser_list_iterator_next (parser_list_iterator_t *);
/* Parser stack. Optimized for pushing bytes.
* Pop functions never throws error. */
void parser_stack_init (parser_context_t *);
void parser_stack_free (parser_context_t *);
void parser_stack_push_uint8 (parser_context_t *, uint8_t);
void parser_stack_pop_uint8 (parser_context_t *);
void parser_stack_push_uint16 (parser_context_t *, uint16_t);
uint16_t parser_stack_pop_uint16 (parser_context_t *);
void parser_stack_push (parser_context_t *, const void *, uint32_t);
void parser_stack_pop (parser_context_t *, void *, uint32_t);
void parser_stack_iterator_skip (parser_stack_iterator_t *, size_t);
void parser_stack_iterator_read (parser_stack_iterator_t *, void *, size_t);
void parser_stack_iterator_write (parser_stack_iterator_t *, const void *, size_t);
/* Compact byte code emitting functions. */
void parser_flush_cbc (parser_context_t *);
void parser_emit_cbc (parser_context_t *, uint16_t);
void parser_emit_cbc_literal (parser_context_t *, uint16_t, uint16_t);
void parser_emit_cbc_literal_from_token (parser_context_t *, uint16_t);
void parser_emit_cbc_call (parser_context_t *, uint16_t, size_t);
void parser_emit_cbc_push_number (parser_context_t *, int);
void parser_emit_cbc_forward_branch (parser_context_t *, uint16_t, parser_branch_t *);
parser_branch_node_t *parser_emit_cbc_forward_branch_item (parser_context_t *, uint16_t, parser_branch_node_t *);
void parser_emit_cbc_backward_branch (parser_context_t *, uint16_t, uint32_t);
void parser_set_branch_to_current_position (parser_context_t *, parser_branch_t *);
void parser_set_breaks_to_current_position (parser_context_t *, parser_branch_node_t *);
void parser_set_continues_to_current_position (parser_context_t *, parser_branch_node_t *);
/* Convenience macros. */
#define parser_emit_cbc_ext(context_p, opcode) \
parser_emit_cbc ((context_p), PARSER_TO_EXT_OPCODE (opcode))
#define parser_emit_cbc_ext_literal(context_p, opcode, literal_index) \
parser_emit_cbc_literal ((context_p), PARSER_TO_EXT_OPCODE (opcode), (literal_index))
#define parser_emit_cbc_ext_call(context_p, opcode, call_arguments) \
parser_emit_cbc_call ((context_p), PARSER_TO_EXT_OPCODE (opcode), (call_arguments))
#define parser_emit_cbc_ext_forward_branch(context_p, opcode, branch_p) \
parser_emit_cbc_forward_branch ((context_p), PARSER_TO_EXT_OPCODE (opcode), (branch_p))
#define parser_emit_cbc_ext_backward_branch(context_p, opcode, offset) \
parser_emit_cbc_backward_branch ((context_p), PARSER_TO_EXT_OPCODE (opcode), (offset))
/* Lexer functions */
void lexer_next_token (parser_context_t *);
void lexer_expect_identifier (parser_context_t *, uint8_t);
void lexer_scan_identifier (parser_context_t *, int);
void lexer_expect_object_literal_id (parser_context_t *, int);
void lexer_construct_literal_object (parser_context_t *, lexer_lit_location_t *, uint8_t);
int lexer_construct_number_object (parser_context_t *, int, int);
void lexer_construct_function_object (parser_context_t *, uint32_t);
void lexer_construct_regexp_object (parser_context_t *, int);
int lexer_same_identifiers (lexer_lit_location_t *, lexer_lit_location_t *);
/* Parser functions. */
void parser_parse_expression (parser_context_t *, int);
void parser_parse_statements (parser_context_t *);
void parser_scan_until (parser_context_t *, lexer_range_t *, lexer_token_type_t);
ecma_compiled_code_t *parser_parse_function (parser_context_t *, uint32_t);
void parser_free_jumps (parser_stack_iterator_t);
/* Error management. */
void parser_raise_error (parser_context_t *, parser_error_t);
/**
* @}
* @}
* @}
*/
#endif /* !JS_PARSER_INTERNAL_H */
+99
View File
@@ -0,0 +1,99 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 JS_PARSER_LIMITS_H
#define JS_PARSER_LIMITS_H
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_internals Internals
* @{
*/
/* Maximum identifier length accepted by the parser.
* Limit: LEXER_MAX_STRING_LENGTH. */
#ifndef PARSER_MAXIMUM_IDENT_LENGTH
#define PARSER_MAXIMUM_IDENT_LENGTH 255
#endif /* PARSER_MAXIMUM_IDENT_LENGTH */
/* Maximum string length.
* Limit: 65535. */
#ifndef PARSER_MAXIMUM_STRING_LENGTH
#define PARSER_MAXIMUM_STRING_LENGTH 65535
#endif /* PARSER_MAXIMUM_STRING_LENGTH */
/* Maximum number of literals.
* Limit: 32767. Recommended: 510, 32767 */
#ifndef PARSER_MAXIMUM_NUMBER_OF_LITERALS
#define PARSER_MAXIMUM_NUMBER_OF_LITERALS 32767
#endif /* PARSER_MAXIMUM_NUMBER_OF_LITERALS */
/* Maximum number of registers.
* Limit: PARSER_MAXIMUM_NUMBER_OF_LITERALS */
#ifndef PARSER_MAXIMUM_NUMBER_OF_REGISTERS
#define PARSER_MAXIMUM_NUMBER_OF_REGISTERS 256
#endif
/* Maximum code size.
* Limit: 16777215. Recommended: 65535, 16777215. */
#ifndef PARSER_MAXIMUM_CODE_SIZE
#define PARSER_MAXIMUM_CODE_SIZE 16777215
#endif
/* Maximum number of values pushed onto the stack by a function.
* Limit: 65500. Recommended: 1024. */
#ifndef PARSER_MAXIMUM_STACK_LIMIT
#define PARSER_MAXIMUM_STACK_LIMIT 1024
#endif /* !PARSER_MAXIMUM_STACK_LIMIT */
/* Checks. */
#if (PARSER_MAXIMUM_STRING_LENGTH < 1) || (PARSER_MAXIMUM_STRING_LENGTH > 65535)
#error "Maximum string length is not within range."
#endif /* (PARSER_MAXIMUM_STRING_LENGTH < 1) || (PARSER_MAXIMUM_STRING_LENGTH > 65535) */
#if (PARSER_MAXIMUM_IDENT_LENGTH < 1) || (PARSER_MAXIMUM_IDENT_LENGTH > PARSER_MAXIMUM_STRING_LENGTH)
#error "Maximum identifier length is not within range."
#endif /* (PARSER_MAXIMUM_IDENT_LENGTH < 1) || (PARSER_MAXIMUM_IDENT_LENGTH > PARSER_MAXIMUM_STRING_LENGTH) */
#if (PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) || (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767)
#error "Maximum number of literals is not within range."
#endif /* (PARSER_MAXIMUM_NUMBER_OF_LITERALS < 1) || (PARSER_MAXIMUM_NUMBER_OF_LITERALS > 32767) */
#if (PARSER_MAXIMUM_NUMBER_OF_REGISTERS > PARSER_MAXIMUM_NUMBER_OF_LITERALS)
#error "Maximum number of registers is not within range."
#endif /* (PARSER_MAXIMUM_NUMBER_OF_REGISTERS > PARSER_MAXIMUM_NUMBER_OF_LITERALS) */
#if (PARSER_MAXIMUM_CODE_SIZE < 4096) || (PARSER_MAXIMUM_CODE_SIZE > 16777215)
#error "Maximum code size is not within range."
#endif /* (PARSER_MAXIMUM_CODE_SIZE < 4096) || (PARSER_MAXIMUM_CODE_SIZE > 16777215) */
#if (PARSER_MAXIMUM_STACK_LIMIT < 16) || (PARSER_MAXIMUM_STACK_LIMIT > 65500)
#error "Maximum function stack usage is not within range."
#endif /* (PARSER_MAXIMUM_STACK_LIMIT < 16) || (PARSER_MAXIMUM_STACK_LIMIT > 65500) */
/**
* @}
* @}
* @}
*/
#endif /* !JS_PARSER_LIMITS_H */
+669
View File
@@ -0,0 +1,669 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 "js-parser-internal.h"
/** \addtogroup mem Memory allocation
* @{
*
* \addtogroup mem_parser Parser memory manager
* @{
*/
/**********************************************************************/
/* Memory allocation */
/**********************************************************************/
/**
* Allocate memory.
*
* @return allocated memory.
*/
void *
parser_malloc (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory */
{
void *result;
JERRY_ASSERT (size > 0);
result = PARSER_MALLOC (size);
if (result == 0)
{
parser_raise_error (context_p, PARSER_ERR_OUT_OF_MEMORY);
}
return result;
} /* parser_malloc */
/**
* Free memory allocated by parser_malloc.
*/
void parser_free (void *ptr) /**< pointer to free */
{
PARSER_FREE (ptr);
} /* parser_free */
/**
* Allocate local memory for short term use.
*
* @return allocated memory.
*/
void *
parser_malloc_local (parser_context_t *context_p, /**< context */
size_t size) /**< size of the memory */
{
void *result;
JERRY_ASSERT (size > 0);
result = PARSER_MALLOC_LOCAL (size);
if (result == 0)
{
parser_raise_error (context_p, PARSER_ERR_OUT_OF_MEMORY);
}
return result;
} /* parser_malloc_local */
/**
* Free memory allocated by parser_malloc_local.
*/
void parser_free_local (void *ptr) /**< pointer to free */
{
PARSER_FREE_LOCAL (ptr);
} /* parser_free_local */
/**********************************************************************/
/* Parser data management functions */
/**********************************************************************/
/**
* Initialize parse data.
*/
static void
parser_data_init (parser_mem_data_t *data_p, /**< memory manager */
uint32_t page_size) /**< size of each page */
{
data_p->first_p = NULL;
data_p->last_p = NULL;
data_p->last_position = page_size;
} /* parser_data_init */
/**
* Free parse data.
*/
static void
parser_data_free (parser_mem_data_t *data_p) /**< memory manager */
{
parser_mem_page_t *page_p = data_p->first_p;
while (page_p != NULL)
{
parser_mem_page_t *next_p = page_p->next_p;
parser_free (page_p);
page_p = next_p;
}
} /* parser_data_free */
/**********************************************************************/
/* Parser byte stream management functions */
/**********************************************************************/
/**
* Initialize byte stream.
*/
void
parser_cbc_stream_init (parser_mem_data_t *data_p) /**< memory manager */
{
parser_data_init (data_p, PARSER_CBC_STREAM_PAGE_SIZE);
} /* parser_cbc_stream_init */
/**
* Free byte stream.
*/
void
parser_cbc_stream_free (parser_mem_data_t *data_p) /**< memory manager */
{
parser_data_free (data_p);
} /* parser_cbc_stream_free */
/**
* Appends a byte at the end of the byte stream.
*/
void
parser_cbc_stream_alloc_page (parser_context_t *context_p, /**< context */
parser_mem_data_t *data_p) /**< memory manager */
{
size_t size = sizeof (parser_mem_page_t *) + PARSER_CBC_STREAM_PAGE_SIZE;
parser_mem_page_t *page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
page_p->next_p = NULL;
data_p->last_position = 0;
if (data_p->last_p != NULL)
{
data_p->last_p->next_p = page_p;
}
else
{
data_p->first_p = page_p;
}
data_p->last_p = page_p;
} /* parser_cbc_stream_alloc_page */
/**********************************************************************/
/* Parser list management functions */
/**********************************************************************/
/**
* Initialize parser list.
*/
void
parser_list_init (parser_list_t *list_p, /**< parser list */
uint32_t item_size, /**< size for each page */
uint32_t item_count) /**< number of items on each page */
{
/* Align to pointer size. */
item_size = (uint32_t) (((item_size) + sizeof (void *) - 1) & ~(sizeof (void *) - 1));
parser_data_init (&list_p->data, item_size * item_count);
list_p->page_size = item_size * item_count;
list_p->item_size = item_size;
list_p->item_count = item_count;
} /* parser_list_init */
/**
* Free parser list.
*/
void
parser_list_free (parser_list_t *list_p) /**< parser list */
{
parser_data_free (&list_p->data);
} /* parser_list_free */
/**
* Reset parser list.
*/
void
parser_list_reset (parser_list_t *list_p) /**< parser list */
{
parser_data_init (&list_p->data, list_p->page_size);
} /* parser_list_reset */
/**
* Allocate space for the next item.
*
* @return pointer to the appended item.
*/
void *
parser_list_append (parser_context_t *context_p, /**< context */
parser_list_t *list_p) /**< parser list */
{
parser_mem_page_t *page_p = list_p->data.last_p;
void *result;
if (list_p->data.last_position + list_p->item_size > list_p->page_size)
{
size_t size = sizeof (parser_mem_page_t *) + list_p->page_size;
page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
page_p->next_p = NULL;
list_p->data.last_position = 0;
if (list_p->data.last_p != NULL)
{
list_p->data.last_p->next_p = page_p;
}
else
{
list_p->data.first_p = page_p;
}
list_p->data.last_p = page_p;
}
result = page_p->bytes + list_p->data.last_position;
list_p->data.last_position += list_p->item_size;
return result;
} /* parser_list_append */
/**
* Return the nth item of the list.
*
* @return pointer to the item.
*/
void *
parser_list_get (parser_list_t *list_p, /**< parser list */
size_t index) /**< item index */
{
size_t item_count = list_p->item_count;
parser_mem_page_t *page_p = list_p->data.first_p;
while (index >= item_count)
{
JERRY_ASSERT (page_p != NULL);
page_p = page_p->next_p;
index -= item_count;
}
JERRY_ASSERT (page_p != NULL);
JERRY_ASSERT (page_p != list_p->data.last_p
|| (index * list_p->item_size < list_p->data.last_position));
return page_p->bytes + (index * list_p->item_size);
} /* parser_list_get */
/**
* Initialize a parser list iterator.
*/
void
parser_list_iterator_init (parser_list_t *list_p, /**< parser list */
parser_list_iterator_t *iterator_p) /**< iterator */
{
iterator_p->list_p = list_p;
iterator_p->current_p = list_p->data.first_p;
iterator_p->current_position = 0;
} /* parser_list_iterator_init */
/**
* Next iterator step.
*
* @return the address of the current item, or NULL at the end.
*/
void *
parser_list_iterator_next (parser_list_iterator_t *iterator_p) /**< iterator */
{
void *result;
if (iterator_p->current_p == NULL)
{
return NULL;
}
result = iterator_p->current_p->bytes + iterator_p->current_position;
iterator_p->current_position += iterator_p->list_p->item_size;
if (iterator_p->current_p->next_p == NULL)
{
if (iterator_p->current_position >= iterator_p->list_p->data.last_position)
{
iterator_p->current_p = NULL;
iterator_p->current_position = 0;
}
}
else if (iterator_p->current_position >= iterator_p->list_p->page_size)
{
iterator_p->current_p = iterator_p->current_p->next_p;
iterator_p->current_position = 0;
}
return result;
} /* parser_list_iterator_next */
/**********************************************************************/
/* Parser stack management functions */
/**********************************************************************/
/* Stack is a reversed storage. */
/**
* Initialize parser stack.
*/
void
parser_stack_init (parser_context_t *context_p) /**< context */
{
parser_data_init (&context_p->stack, PARSER_STACK_PAGE_SIZE);
context_p->free_page_p = NULL;
} /* parser_stack_init */
/**
* Free parser stack.
*/
void
parser_stack_free (parser_context_t *context_p) /**< context */
{
parser_data_free (&context_p->stack);
if (context_p->free_page_p != NULL)
{
parser_free (context_p->free_page_p);
}
} /* parser_stack_free */
/**
* Pushes an uint8_t value onto the stack.
*/
void
parser_stack_push_uint8 (parser_context_t *context_p, /**< context */
uint8_t uint8_value) /**< value pushed onto the stack */
{
parser_mem_page_t *page_p = context_p->stack.first_p;
/* This assert might trigger false positive valgrind errors, when
* parser_stack_push() pushes not fully initialized structures.
* More precisely when the last byte of the structure is uninitialized. */
JERRY_ASSERT (page_p == NULL
|| context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
if (context_p->stack.last_position >= PARSER_STACK_PAGE_SIZE)
{
if (context_p->free_page_p != NULL)
{
page_p = context_p->free_page_p;
context_p->free_page_p = NULL;
}
else
{
size_t size = sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE;
page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
}
page_p->next_p = context_p->stack.first_p;
context_p->stack.last_position = 0;
context_p->stack.first_p = page_p;
}
page_p->bytes[context_p->stack.last_position++] = uint8_value;
context_p->stack_top_uint8 = uint8_value;
} /* parser_stack_push_uint8 */
/**
* Pops the last uint8_t value from the stack.
*/
void
parser_stack_pop_uint8 (parser_context_t *context_p) /**< context */
{
parser_mem_page_t *page_p = context_p->stack.first_p;
JERRY_ASSERT (page_p != NULL
&& context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
context_p->stack.last_position--;
if (context_p->stack.last_position == 0)
{
context_p->stack.first_p = page_p->next_p;
context_p->stack.last_position = PARSER_STACK_PAGE_SIZE;
if (context_p->free_page_p == NULL)
{
context_p->free_page_p = page_p;
}
else
{
parser_free (page_p);
}
page_p = context_p->stack.first_p;
JERRY_ASSERT (page_p != NULL);
}
context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 1];
} /* parser_stack_pop_uint8 */
/**
* Pushes an uint16_t value onto the stack.
*/
void
parser_stack_push_uint16 (parser_context_t *context_p, /**< context */
uint16_t uint16_value) /**< value pushed onto the stack */
{
if (context_p->stack.last_position + 2 <= PARSER_STACK_PAGE_SIZE)
{
parser_mem_page_t *page_p = context_p->stack.first_p;
JERRY_ASSERT (page_p != NULL
&& context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
page_p->bytes[context_p->stack.last_position++] = (uint8_t) (uint16_value >> 8);
page_p->bytes[context_p->stack.last_position++] = (uint8_t) uint16_value;
context_p->stack_top_uint8 = (uint8_t) uint16_value;
}
else
{
parser_stack_push_uint8 (context_p, (uint8_t) (uint16_value >> 8));
parser_stack_push_uint8 (context_p, (uint8_t) uint16_value);
}
} /* parser_stack_push_uint16 */
/**
* Pops the last uint16_t value from the stack.
*
* @return the value popped from the stack.
*/
uint16_t
parser_stack_pop_uint16 (parser_context_t *context_p) /**< context */
{
uint32_t value = context_p->stack_top_uint8;
if (context_p->stack.last_position >= 3)
{
parser_mem_page_t *page_p = context_p->stack.first_p;
JERRY_ASSERT (page_p != NULL
&& context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]);
value |= ((uint32_t) page_p->bytes[context_p->stack.last_position - 2]) << 8;
context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 3];
context_p->stack.last_position -= 2;
}
else
{
parser_stack_pop_uint8 (context_p);
value |= ((uint32_t) context_p->stack_top_uint8) << 8;
parser_stack_pop_uint8 (context_p);
}
return (uint16_t) value;
} /* parser_stack_pop_uint16 */
/**
* Pushes a data onto the stack.
*/
void
parser_stack_push (parser_context_t *context_p, /**< context */
const void *data_p, /* data pushed onto the stack */
uint32_t length) /* length of the data */
{
uint32_t fragment_length = PARSER_STACK_PAGE_SIZE - context_p->stack.last_position;
const uint8_t *bytes_p = (const uint8_t *) data_p;
parser_mem_page_t *page_p;
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
context_p->stack_top_uint8 = bytes_p[length - 1];
if (fragment_length > 0)
{
/* Fill the remaining bytes. */
if (fragment_length > length)
{
fragment_length = length;
}
memcpy (context_p->stack.first_p->bytes + context_p->stack.last_position,
bytes_p,
fragment_length);
if (fragment_length == length)
{
context_p->stack.last_position += length;
return;
}
bytes_p += fragment_length;
length -= fragment_length;
}
if (context_p->free_page_p != NULL)
{
page_p = context_p->free_page_p;
context_p->free_page_p = NULL;
}
else
{
size_t size = sizeof (parser_mem_page_t *) + PARSER_STACK_PAGE_SIZE;
page_p = (parser_mem_page_t *) parser_malloc (context_p, size);
}
page_p->next_p = context_p->stack.first_p;
context_p->stack.first_p = page_p;
memcpy (page_p->bytes, bytes_p, length);
context_p->stack.last_position = length;
} /* parser_stack_push */
/**
* Pop bytes from the top of the stack.
*/
void
parser_stack_pop (parser_context_t *context_p, /**< context */
void *data_p, /* destination buffer, can be NULL */
uint32_t length) /* length of the data */
{
uint8_t *bytes_p = (uint8_t *) data_p;
parser_mem_page_t *page_p = context_p->stack.first_p;
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
if (context_p->stack.last_position > length)
{
context_p->stack.last_position -= length;
context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 1];
if (bytes_p != NULL)
{
memcpy (bytes_p, context_p->stack.first_p->bytes + context_p->stack.last_position, length);
}
return;
}
JERRY_ASSERT (page_p->next_p != NULL);
length -= context_p->stack.last_position;
if (bytes_p != NULL)
{
memcpy (bytes_p + length, page_p->bytes, context_p->stack.last_position);
}
context_p->stack.first_p = page_p->next_p;
context_p->stack.last_position = PARSER_STACK_PAGE_SIZE - length;
context_p->stack_top_uint8 = page_p->next_p->bytes[context_p->stack.last_position - 1];
if (bytes_p != NULL && length > 0)
{
memcpy (bytes_p, page_p->next_p->bytes + context_p->stack.last_position, length);
}
JERRY_ASSERT (context_p->stack.last_position > 0);
if (context_p->free_page_p == NULL)
{
context_p->free_page_p = page_p;
}
else
{
parser_free (page_p);
}
} /* parser_stack_pop */
/**
* Skip the next n bytes of the stack.
*/
void
parser_stack_iterator_skip (parser_stack_iterator_t *iterator, /**< iterator */
size_t length) /**< number of skipped bytes */
{
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
if (length < iterator->current_position)
{
iterator->current_position -= length;
}
else
{
iterator->current_position = PARSER_STACK_PAGE_SIZE - (length - iterator->current_position);
iterator->current_p = iterator->current_p->next_p;
}
} /* parser_stack_iterator_skip */
/**
* Read bytes from the stack.
*/
void
parser_stack_iterator_read (parser_stack_iterator_t *iterator, /**< iterator */
void *data_p, /* destination buffer */
size_t length) /* length of the data */
{
uint8_t *bytes_p = (uint8_t *) data_p;
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
if (length <= iterator->current_position)
{
memcpy (bytes_p,
iterator->current_p->bytes + iterator->current_position - length,
length);
}
else
{
JERRY_ASSERT (iterator->current_p->next_p != NULL);
length -= iterator->current_position;
memcpy (bytes_p + length,
iterator->current_p->bytes,
iterator->current_position);
memcpy (bytes_p,
iterator->current_p->next_p->bytes + PARSER_STACK_PAGE_SIZE - length,
length);
}
} /* parser_stack_iterator_read */
/**
* Write bytes onto the stack.
*/
void
parser_stack_iterator_write (parser_stack_iterator_t *iterator, /**< iterator */
const void *data_p, /* destination buffer */
size_t length) /* length of the data */
{
const uint8_t *bytes_p = (const uint8_t *) data_p;
JERRY_ASSERT (length < PARSER_STACK_PAGE_SIZE && length > 0);
if (length <= iterator->current_position)
{
memcpy (iterator->current_p->bytes + iterator->current_position - length,
bytes_p,
length);
}
else
{
JERRY_ASSERT (iterator->current_p->next_p != NULL);
length -= iterator->current_position;
memcpy (iterator->current_p->bytes,
bytes_p + length,
iterator->current_position);
memcpy (iterator->current_p->next_p->bytes + PARSER_STACK_PAGE_SIZE - length,
bytes_p,
length);
}
} /* parser_stack_iterator_write */
/**
* @}
* @}
*/
+678
View File
@@ -0,0 +1,678 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 "js-parser-internal.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_scanner Scanner
* @{
*/
/**
* Scan mode types types.
*/
typedef enum
{
SCAN_MODE_PRIMARY_EXPRESSION, /**< scanning primary expression */
SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW, /**< scanning primary expression after new */
SCAN_MODE_POST_PRIMARY_EXPRESSION, /**< scanning post primary expression */
SCAN_MODE_PRIMARY_EXPRESSION_END, /**< scanning prymary expression end */
SCAN_MODE_STATEMENT, /**< scanning statement */
SCAN_MODE_FUNCTION_ARGUMENTS, /**< scanning function arguments */
SCAN_MODE_PROPERTY_NAME, /**< scanning property name */
} scan_modes_t;
/**
* Scan stack mode types types.
*/
typedef enum
{
SCAN_STACK_HEAD, /**< head */
SCAN_STACK_PAREN_EXPRESSION, /**< parent expression group */
SCAN_STACK_PAREN_STATEMENT, /**< parent stetement group */
SCAN_STACK_COLON_EXPRESSION, /**< colon expression group */
SCAN_STACK_COLON_STATEMENT, /**< colon statement group*/
SCAN_STACK_SQUARE_BRACKETED_EXPRESSION, /**< square bracketed expression group */
SCAN_STACK_OBJECT_LITERAL, /**< object literal group */
SCAN_STACK_BLOCK_STATEMENT, /**< block statement group */
SCAN_STACK_BLOCK_EXPRESSION, /**< block expression group*/
SCAN_STACK_BLOCK_PROPERTY, /**< block property group */
} scan_stack_modes_t;
/**
* Scan primary expression.
*
* @return PARSER_TRUE for continue, PARSER_FALSE for break
*/
static int
parser_scan_primary_expression (parser_context_t *context_p, /**< context */
lexer_token_type_t type, /**< current token type */
scan_stack_modes_t stack_top, /**< current stack top */
scan_modes_t *mode) /**< scan mode */
{
switch (type)
{
case LEXER_KEYW_NEW:
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW;
break;
}
case LEXER_DIVIDE:
case LEXER_ASSIGN_DIVIDE:
{
lexer_construct_regexp_object (context_p, PARSER_TRUE);
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
case LEXER_KEYW_FUNCTION:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_EXPRESSION);
*mode = SCAN_MODE_FUNCTION_ARGUMENTS;
break;
}
case LEXER_LEFT_PAREN:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
case LEXER_LEFT_SQUARE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
case LEXER_LEFT_BRACE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL);
*mode = SCAN_MODE_PROPERTY_NAME;
return PARSER_TRUE;
}
case LEXER_LITERAL:
case LEXER_KEYW_THIS:
case LEXER_LIT_TRUE:
case LEXER_LIT_FALSE:
case LEXER_LIT_NULL:
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
case LEXER_RIGHT_SQUARE:
{
if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION)
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
parser_stack_pop_uint8 (context_p);
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
case LEXER_COMMA:
{
if (stack_top != SCAN_STACK_SQUARE_BRACKETED_EXPRESSION)
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
case LEXER_RIGHT_PAREN:
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
if (stack_top == SCAN_STACK_PAREN_STATEMENT)
{
*mode = SCAN_MODE_STATEMENT;
}
else if (stack_top != SCAN_STACK_PAREN_EXPRESSION)
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
parser_stack_pop_uint8 (context_p);
break;
}
case LEXER_SEMICOLON:
{
/* Needed by for (;;) statements. */
if (stack_top != SCAN_STACK_PAREN_STATEMENT)
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
default:
{
parser_raise_error (context_p, PARSER_ERR_PRIMARY_EXP_EXPECTED);
}
}
return PARSER_FALSE;
} /* parser_scan_primary_expression */
/**
* Scan the tokens after the primary expression.
*
* @return PARSER_TRUE for break, PARSER_FALSE for fall through
*/
static int
parser_scan_post_primary_expression (parser_context_t *context_p, /**< context */
lexer_token_type_t type, /**< current token type */
scan_modes_t *mode) /**< scan mode */
{
switch (type)
{
case LEXER_DOT:
{
lexer_scan_identifier (context_p, PARSER_FALSE);
return PARSER_TRUE;
}
case LEXER_LEFT_PAREN:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_TRUE;
}
case LEXER_LEFT_SQUARE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_SQUARE_BRACKETED_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_TRUE;
}
case LEXER_INCREASE:
case LEXER_DECREASE:
{
if (!context_p->token.was_newline)
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION_END;
return PARSER_TRUE;
}
/* FALLTHRU */
}
default:
{
break;
}
}
return PARSER_FALSE;
} /* parser_scan_post_primary_expression */
/**
* Scan the tokens after the primary expression.
*
* @return PARSER_TRUE for continue, PARSER_FALSE for break
*/
static int
parser_scan_primary_expression_end (parser_context_t *context_p, /**< context */
lexer_token_type_t type, /**< current token type */
scan_stack_modes_t stack_top, /**< current stack top */
lexer_token_type_t end_type, /**< terminator token type */
scan_modes_t *mode) /**< scan mode */
{
switch (type)
{
case LEXER_QUESTION_MARK:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_EXPRESSION);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_COMMA:
{
if (stack_top == SCAN_STACK_OBJECT_LITERAL)
{
*mode = SCAN_MODE_PROPERTY_NAME;
return PARSER_TRUE;
}
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_COLON:
{
if (stack_top == SCAN_STACK_COLON_EXPRESSION
|| stack_top == SCAN_STACK_COLON_STATEMENT)
{
if (stack_top == SCAN_STACK_COLON_EXPRESSION)
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
}
else
{
*mode = SCAN_MODE_STATEMENT;
}
parser_stack_pop_uint8 (context_p);
return PARSER_FALSE;
}
/* FALLTHRU */
}
default:
{
break;
}
}
if (LEXER_IS_BINARY_OP_TOKEN (type)
|| (type == LEXER_SEMICOLON && stack_top == SCAN_STACK_PAREN_STATEMENT))
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
if ((type == LEXER_RIGHT_SQUARE && stack_top == SCAN_STACK_SQUARE_BRACKETED_EXPRESSION)
|| (type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_PAREN_EXPRESSION)
|| (type == LEXER_RIGHT_BRACE && stack_top == SCAN_STACK_OBJECT_LITERAL))
{
parser_stack_pop_uint8 (context_p);
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
*mode = SCAN_MODE_STATEMENT;
if (type == LEXER_RIGHT_PAREN && stack_top == SCAN_STACK_PAREN_STATEMENT)
{
parser_stack_pop_uint8 (context_p);
return PARSER_FALSE;
}
/* Check whether we can enter to statement mode. */
if (stack_top != SCAN_STACK_BLOCK_STATEMENT
&& stack_top != SCAN_STACK_BLOCK_EXPRESSION
&& !(stack_top == SCAN_STACK_HEAD && end_type == LEXER_SCAN_SWITCH))
{
parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION);
}
if (type == LEXER_RIGHT_BRACE
|| context_p->token.was_newline)
{
return PARSER_TRUE;
}
if (type != LEXER_SEMICOLON)
{
parser_raise_error (context_p, PARSER_ERR_INVALID_EXPRESSION);
}
return PARSER_FALSE;
} /* parser_scan_primary_expression_end */
/**
* Scan statements.
*
* @return PARSER_TRUE for continue, PARSER_FALSE for break
*/
static int
parser_scan_statement (parser_context_t *context_p, /**< context */
lexer_token_type_t type, /**< current token type */
scan_stack_modes_t stack_top, /**< current stack top */
scan_modes_t *mode) /**< scan mode */
{
switch (type)
{
case LEXER_SEMICOLON:
case LEXER_KEYW_ELSE:
case LEXER_KEYW_DO:
case LEXER_KEYW_TRY:
case LEXER_KEYW_FINALLY:
case LEXER_KEYW_DEBUGGER:
{
return PARSER_FALSE;
}
case LEXER_KEYW_IF:
case LEXER_KEYW_WHILE:
case LEXER_KEYW_WITH:
case LEXER_KEYW_SWITCH:
case LEXER_KEYW_CATCH:
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
}
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_STATEMENT);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_KEYW_FOR:
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
}
lexer_next_token (context_p);
parser_stack_push_uint8 (context_p, SCAN_STACK_PAREN_STATEMENT);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (context_p->token.type == LEXER_KEYW_VAR)
{
return PARSER_FALSE;
}
return PARSER_TRUE;
}
case LEXER_KEYW_VAR:
case LEXER_KEYW_THROW:
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_KEYW_RETURN:
{
lexer_next_token (context_p);
if (!context_p->token.was_newline
&& context_p->token.type != LEXER_SEMICOLON)
{
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
}
return PARSER_TRUE;
}
case LEXER_KEYW_BREAK:
case LEXER_KEYW_CONTINUE:
{
lexer_next_token (context_p);
if (!context_p->token.was_newline
&& context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
return PARSER_FALSE;
}
return PARSER_TRUE;
}
case LEXER_KEYW_DEFAULT:
{
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
return PARSER_FALSE;
}
case LEXER_KEYW_CASE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_COLON_STATEMENT);
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
return PARSER_FALSE;
}
case LEXER_RIGHT_BRACE:
{
if (stack_top == SCAN_STACK_BLOCK_STATEMENT
|| stack_top == SCAN_STACK_BLOCK_EXPRESSION
|| stack_top == SCAN_STACK_BLOCK_PROPERTY)
{
parser_stack_pop_uint8 (context_p);
if (stack_top == SCAN_STACK_BLOCK_EXPRESSION)
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
}
else if (stack_top == SCAN_STACK_BLOCK_PROPERTY)
{
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COMMA
&& context_p->token.type != LEXER_RIGHT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED);
}
return PARSER_TRUE;
}
return PARSER_FALSE;
}
break;
}
case LEXER_LEFT_BRACE:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT);
return PARSER_FALSE;
}
case LEXER_KEYW_FUNCTION:
{
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_STATEMENT);
*mode = SCAN_MODE_FUNCTION_ARGUMENTS;
return PARSER_FALSE;
}
default:
{
break;
}
}
*mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_next_token (context_p);
if (context_p->token.type == LEXER_COLON)
{
*mode = SCAN_MODE_STATEMENT;
return PARSER_FALSE;
}
*mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
}
return PARSER_TRUE;
} /* parser_scan_statement */
/**
* Pre-scan for token(s).
*/
void
parser_scan_until (parser_context_t *context_p, /**< context */
lexer_range_t *range_p, /**< destination range */
lexer_token_type_t end_type) /**< terminator token type */
{
scan_modes_t mode;
lexer_token_type_t end_type_b = end_type;
range_p->source_p = context_p->source_p;
range_p->source_end_p = context_p->source_p;
range_p->line = context_p->line;
range_p->column = context_p->column;
mode = SCAN_MODE_PRIMARY_EXPRESSION;
if (end_type == LEXER_KEYW_CASE)
{
end_type = LEXER_SCAN_SWITCH;
end_type_b = LEXER_SCAN_SWITCH;
mode = SCAN_MODE_STATEMENT;
}
else
{
lexer_next_token (context_p);
if (end_type == LEXER_KEYW_IN)
{
end_type_b = LEXER_SEMICOLON;
if (context_p->token.type == LEXER_KEYW_VAR)
{
lexer_next_token (context_p);
}
}
}
parser_stack_push_uint8 (context_p, SCAN_STACK_HEAD);
while (PARSER_TRUE)
{
lexer_token_type_t type = (lexer_token_type_t) context_p->token.type;
scan_stack_modes_t stack_top = (scan_stack_modes_t) context_p->stack_top_uint8;
if (type == LEXER_EOS)
{
parser_raise_error (context_p, PARSER_ERR_EXPRESSION_EXPECTED);
}
if (stack_top == SCAN_STACK_HEAD
&& (type == end_type || type == end_type_b))
{
parser_stack_pop_uint8 (context_p);
return;
}
switch (mode)
{
case SCAN_MODE_PRIMARY_EXPRESSION:
{
if (type == LEXER_ADD
|| type == LEXER_SUBTRACT
|| LEXER_IS_UNARY_OP_TOKEN (type))
{
break;
}
/* FALLTHRU */
}
case SCAN_MODE_PRIMARY_EXPRESSION_AFTER_NEW:
{
if (parser_scan_primary_expression (context_p, type, stack_top, &mode))
{
continue;
}
break;
}
case SCAN_MODE_POST_PRIMARY_EXPRESSION:
{
if (parser_scan_post_primary_expression (context_p, type, &mode))
{
break;
}
/* FALLTHRU */
}
case SCAN_MODE_PRIMARY_EXPRESSION_END:
{
if (parser_scan_primary_expression_end (context_p, type, stack_top, end_type, &mode))
{
continue;
}
break;
}
case SCAN_MODE_STATEMENT:
{
if (end_type == LEXER_SCAN_SWITCH
&& stack_top == SCAN_STACK_HEAD
&& (type == LEXER_KEYW_DEFAULT || type == LEXER_KEYW_CASE || type == LEXER_RIGHT_BRACE))
{
parser_stack_pop_uint8 (context_p);
return;
}
if (parser_scan_statement (context_p, type, stack_top, &mode))
{
continue;
}
break;
}
case SCAN_MODE_FUNCTION_ARGUMENTS:
{
JERRY_ASSERT (stack_top == SCAN_STACK_BLOCK_STATEMENT
|| stack_top == SCAN_STACK_BLOCK_EXPRESSION
|| stack_top == SCAN_STACK_BLOCK_PROPERTY);
if (context_p->token.type == LEXER_LITERAL
&& context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
{
lexer_next_token (context_p);
}
if (context_p->token.type != LEXER_LEFT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_ARGUMENT_LIST_EXPECTED);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
while (PARSER_TRUE)
{
if (context_p->token.type != LEXER_LITERAL
|| context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
{
parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COMMA)
{
break;
}
lexer_next_token (context_p);
}
}
if (context_p->token.type != LEXER_RIGHT_PAREN)
{
parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_LEFT_BRACE)
{
parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
}
mode = SCAN_MODE_STATEMENT;
break;
}
case SCAN_MODE_PROPERTY_NAME:
{
JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL);
lexer_scan_identifier (context_p, PARSER_TRUE);
if (context_p->token.type == LEXER_RIGHT_BRACE)
{
parser_stack_pop_uint8 (context_p);
mode = SCAN_MODE_POST_PRIMARY_EXPRESSION;
break;
}
if (context_p->token.type == LEXER_PROPERTY_GETTER
|| context_p->token.type == LEXER_PROPERTY_SETTER)
{
parser_stack_push_uint8 (context_p, SCAN_STACK_BLOCK_PROPERTY);
mode = SCAN_MODE_FUNCTION_ARGUMENTS;
break;
}
lexer_next_token (context_p);
if (context_p->token.type != LEXER_COLON)
{
parser_raise_error (context_p, PARSER_ERR_COLON_EXPECTED);
}
mode = SCAN_MODE_PRIMARY_EXPRESSION;
break;
}
}
range_p->source_end_p = context_p->source_p;
lexer_next_token (context_p);
}
} /* parser_scan_until */
/**
* @}
* @}
* @}
*/
File diff suppressed because it is too large Load Diff
+942
View File
@@ -0,0 +1,942 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 "js-parser-internal.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_utils Utility
* @{
*/
/**********************************************************************/
/* Emitting byte codes */
/**********************************************************************/
/**
* Append two bytes to the cbc stream.
*/
static void
parser_emit_two_bytes (parser_context_t *context_p, /**< context */
uint8_t first_byte, /**< first byte */
uint8_t second_byte) /**< second byte */
{
uint32_t last_position = context_p->byte_code.last_position;
if (last_position + 2 <= PARSER_CBC_STREAM_PAGE_SIZE)
{
parser_mem_page_t *page_p = context_p->byte_code.last_p;
page_p->bytes[last_position] = first_byte;
page_p->bytes[last_position + 1] = second_byte;
context_p->byte_code.last_position = last_position + 2;
}
else if (last_position >= PARSER_CBC_STREAM_PAGE_SIZE)
{
parser_mem_page_t *page_p;
parser_cbc_stream_alloc_page (context_p, &context_p->byte_code);
page_p = context_p->byte_code.last_p;
page_p->bytes[0] = first_byte;
page_p->bytes[1] = second_byte;
context_p->byte_code.last_position = 2;
}
else
{
context_p->byte_code.last_p->bytes[PARSER_CBC_STREAM_PAGE_SIZE - 1] = first_byte;
parser_cbc_stream_alloc_page (context_p, &context_p->byte_code);
context_p->byte_code.last_p->bytes[0] = second_byte;
context_p->byte_code.last_position = 1;
}
} /* parser_emit_two_bytes */
#define PARSER_APPEND_TO_BYTE_CODE(context_p, byte) \
if ((context_p)->byte_code.last_position >= PARSER_CBC_STREAM_PAGE_SIZE) \
{ \
parser_cbc_stream_alloc_page ((context_p), &(context_p)->byte_code); \
} \
(context_p)->byte_code.last_p->bytes[(context_p)->byte_code.last_position++] = (uint8_t) (byte)
/**
* Append the current byte code to the stream
*/
void
parser_flush_cbc (parser_context_t *context_p) /**< context */
{
uint8_t flags;
if (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE)
{
return;
}
context_p->status_flags |= PARSER_NO_END_LABEL;
if (PARSER_IS_BASIC_OPCODE (context_p->last_cbc_opcode))
{
cbc_opcode_t opcode = (cbc_opcode_t) context_p->last_cbc_opcode;
flags = cbc_flags[opcode];
PARSER_APPEND_TO_BYTE_CODE (context_p, opcode);
context_p->byte_code_size++;
}
else
{
cbc_ext_opcode_t opcode = (cbc_ext_opcode_t) PARSER_GET_EXT_OPCODE (context_p->last_cbc_opcode);
flags = cbc_ext_flags[opcode];
parser_emit_two_bytes (context_p, CBC_EXT_OPCODE, opcode);
context_p->byte_code_size += 2;
}
JERRY_ASSERT ((flags >> CBC_STACK_ADJUST_SHIFT) >= CBC_STACK_ADJUST_BASE
|| (CBC_STACK_ADJUST_BASE - (flags >> CBC_STACK_ADJUST_SHIFT)) <= context_p->stack_depth);
PARSER_PLUS_EQUAL_U16 (context_p->stack_depth, CBC_STACK_ADJUST_VALUE (flags));
if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2))
{
uint16_t literal_index = context_p->last_cbc.literal_index;
parser_emit_two_bytes (context_p,
(uint8_t) (literal_index & 0xff),
(uint8_t) (literal_index >> 8));
context_p->byte_code_size += 2;
}
if (flags & CBC_HAS_LITERAL_ARG2)
{
uint16_t literal_index = context_p->last_cbc.value;
parser_emit_two_bytes (context_p,
(uint8_t) (literal_index & 0xff),
(uint8_t) (literal_index >> 8));
context_p->byte_code_size += 2;
if (!(flags & CBC_HAS_LITERAL_ARG))
{
literal_index = context_p->last_cbc.third_literal_index;
parser_emit_two_bytes (context_p,
(uint8_t) (literal_index & 0xff),
(uint8_t) (literal_index >> 8));
context_p->byte_code_size += 2;
}
}
if (flags & CBC_HAS_BYTE_ARG)
{
uint8_t byte_argument = (uint8_t) context_p->last_cbc.value;
JERRY_ASSERT (context_p->last_cbc.value <= CBC_MAXIMUM_BYTE_VALUE);
if (flags & CBC_POP_STACK_BYTE_ARG)
{
JERRY_ASSERT (context_p->stack_depth >= byte_argument);
PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, byte_argument);
}
PARSER_APPEND_TO_BYTE_CODE (context_p, byte_argument);
context_p->byte_code_size++;
}
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
const char *name_p;
if (PARSER_IS_BASIC_OPCODE (context_p->last_cbc_opcode))
{
name_p = cbc_names[context_p->last_cbc_opcode];
}
else
{
name_p = cbc_ext_names[PARSER_GET_EXT_OPCODE (context_p->last_cbc_opcode)];
}
printf (" [%3d] %s", (int) context_p->stack_depth, name_p);
if (flags & (CBC_HAS_LITERAL_ARG | CBC_HAS_LITERAL_ARG2))
{
uint16_t literal_index = context_p->last_cbc.literal_index;
lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
printf (" idx:%d->", literal_index);
util_print_literal (literal_p);
}
if (flags & CBC_HAS_LITERAL_ARG2)
{
uint16_t literal_index = context_p->last_cbc.value;
lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
printf (" idx:%d->", literal_index);
util_print_literal (literal_p);
if (!(flags & CBC_HAS_LITERAL_ARG))
{
literal_index = context_p->last_cbc.third_literal_index;
lexer_literal_t *literal_p = PARSER_GET_LITERAL (literal_index);
printf (" idx:%d->", literal_index);
util_print_literal (literal_p);
}
}
if (flags & CBC_HAS_BYTE_ARG)
{
printf (" byte_arg:%d", (int) context_p->last_cbc.value);
}
printf ("\n");
}
#endif /* PARSER_DUMP_BYTE_CODE */
if (context_p->stack_depth > context_p->stack_limit)
{
context_p->stack_limit = context_p->stack_depth;
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
} /* parser_flush_cbc */
/**
* Append a byte code
*/
void
parser_emit_cbc (parser_context_t *context_p, /**< context */
uint16_t opcode) /**< opcode */
{
JERRY_ASSERT (PARSER_ARGS_EQ (opcode, 0));
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->last_cbc_opcode = opcode;
} /* parser_emit_cbc */
/**
* Append a byte code with a literal argument
*/
void
parser_emit_cbc_literal (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
uint16_t literal_index) /**< literal index */
{
JERRY_ASSERT (PARSER_ARGS_EQ (opcode, CBC_HAS_LITERAL_ARG));
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->last_cbc_opcode = opcode;
context_p->last_cbc.literal_index = literal_index;
context_p->last_cbc.literal_type = LEXER_UNUSED_LITERAL;
context_p->last_cbc.literal_object_type = LEXER_LITERAL_OBJECT_ANY;
} /* parser_emit_cbc_literal */
/**
* Append a byte code with the current literal argument
*/
void
parser_emit_cbc_literal_from_token (parser_context_t *context_p, /**< context */
uint16_t opcode) /**< opcode */
{
JERRY_ASSERT (PARSER_ARGS_EQ (opcode, CBC_HAS_LITERAL_ARG));
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->last_cbc_opcode = opcode;
context_p->last_cbc.literal_index = context_p->lit_object.index;
context_p->last_cbc.literal_type = context_p->token.lit_location.type;
context_p->last_cbc.literal_object_type = context_p->lit_object.type;
} /* parser_emit_cbc_literal_from_token */
/**
* Append a byte code with a call argument
*/
void
parser_emit_cbc_call (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
size_t call_arguments) /**< number of arguments */
{
JERRY_ASSERT (PARSER_ARGS_EQ (opcode, CBC_HAS_BYTE_ARG));
JERRY_ASSERT (call_arguments <= CBC_MAXIMUM_BYTE_VALUE);
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->last_cbc_opcode = opcode;
context_p->last_cbc.value = (uint16_t) call_arguments;
} /* parser_emit_cbc_call */
/**
* Append a push number 1/2 byte code
*/
void
parser_emit_cbc_push_number (parser_context_t *context_p, /**< context */
int is_negative_number) /**< sign is negative */
{
uint16_t value = context_p->lit_object.index;
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
JERRY_ASSERT (value < CBC_PUSH_NUMBER_1_RANGE_END);
JERRY_ASSERT (CBC_STACK_ADJUST_VALUE (cbc_flags[CBC_PUSH_NUMBER_1]) == 1);
context_p->stack_depth++;
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
int real_value = value;
if (is_negative_number)
{
real_value = -real_value;
}
printf (" [%3d] %s number:%d\n", (int) context_p->stack_depth, cbc_names[CBC_PUSH_NUMBER_1], real_value);
}
#endif /* PARSER_DUMP_BYTE_CODE */
if (is_negative_number)
{
PARSER_PLUS_EQUAL_U16 (value, CBC_PUSH_NUMBER_1_RANGE_END);
}
parser_emit_two_bytes (context_p,
CBC_PUSH_NUMBER_1,
(uint8_t) value);
context_p->byte_code_size += 2;
if (context_p->stack_depth > context_p->stack_limit)
{
context_p->stack_limit = context_p->stack_depth;
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
} /* parser_emit_cbc_push_number */
/**
* Append a byte code with a branch argument
*/
void
parser_emit_cbc_forward_branch (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
parser_branch_t *branch_p) /**< branch result */
{
uint8_t flags;
uint32_t extra_byte_code_increase;
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->status_flags |= PARSER_NO_END_LABEL;
if (PARSER_IS_BASIC_OPCODE (opcode))
{
flags = cbc_flags[opcode];
extra_byte_code_increase = 0;
}
else
{
PARSER_APPEND_TO_BYTE_CODE (context_p, CBC_EXT_OPCODE);
opcode = (uint16_t) PARSER_GET_EXT_OPCODE (opcode);
flags = cbc_ext_flags[opcode];
extra_byte_code_increase = 1;
}
JERRY_ASSERT (flags & CBC_HAS_BRANCH_ARG);
JERRY_ASSERT (CBC_BRANCH_IS_FORWARD (flags));
JERRY_ASSERT (CBC_BRANCH_OFFSET_LENGTH (opcode) == 1);
/* Branch opcodes never push anything onto the stack. */
JERRY_ASSERT ((flags >> CBC_STACK_ADJUST_SHIFT) >= CBC_STACK_ADJUST_BASE
|| (CBC_STACK_ADJUST_BASE - (flags >> CBC_STACK_ADJUST_SHIFT)) <= context_p->stack_depth);
PARSER_PLUS_EQUAL_U16 (context_p->stack_depth, CBC_STACK_ADJUST_VALUE (flags));
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
if (extra_byte_code_increase == 0)
{
printf (" [%3d] %s\n", (int) context_p->stack_depth, cbc_names[opcode]);
}
else
{
printf (" [%3d] %s\n", (int) context_p->stack_depth, cbc_ext_names[opcode]);
}
}
#endif /* PARSER_DUMP_BYTE_CODE */
#if PARSER_MAXIMUM_CODE_SIZE <= 65535
opcode++;
#else /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
PARSER_PLUS_EQUAL_U16 (opcode, 2);
#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
parser_emit_two_bytes (context_p, (uint8_t) opcode, 0);
branch_p->page_p = context_p->byte_code.last_p;
branch_p->offset = (context_p->byte_code.last_position - 1) | (context_p->byte_code_size << 8);
context_p->byte_code_size += extra_byte_code_increase;
#if PARSER_MAXIMUM_CODE_SIZE <= 65535
PARSER_APPEND_TO_BYTE_CODE (context_p, 0);
context_p->byte_code_size += 3;
#else /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
parser_emit_two_bytes (context_p, 0, 0);
context_p->byte_code_size += 4;
#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
if (context_p->stack_depth > context_p->stack_limit)
{
context_p->stack_limit = context_p->stack_depth;
if (context_p->stack_limit > PARSER_MAXIMUM_STACK_LIMIT)
{
parser_raise_error (context_p, PARSER_ERR_STACK_LIMIT_REACHED);
}
}
} /* parser_emit_cbc_forward_branch */
/**
* Append a branch byte code and create an item
*/
parser_branch_node_t *
parser_emit_cbc_forward_branch_item (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
parser_branch_node_t *next_p) /**< next branch */
{
parser_branch_t branch;
parser_branch_node_t *new_item;
/* Since byte code insertion may throw an out-of-memory error,
* the branch is constructed locally, and copied later. */
parser_emit_cbc_forward_branch (context_p, opcode, &branch);
new_item = (parser_branch_node_t *) parser_malloc (context_p, sizeof (parser_branch_node_t));
new_item->branch = branch;
new_item->next_p = next_p;
return new_item;
} /* parser_emit_cbc_forward_branch_item */
/**
* Append a byte code with a branch argument
*/
void
parser_emit_cbc_backward_branch (parser_context_t *context_p, /**< context */
uint16_t opcode, /**< opcode */
uint32_t offset) /**< destination offset */
{
uint8_t flags;
#ifdef PARSER_DUMP_BYTE_CODE
const char *name;
#endif /* PARSER_DUMP_BYTE_CODE */
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->status_flags |= PARSER_NO_END_LABEL;
offset = context_p->byte_code_size - offset;
if (PARSER_IS_BASIC_OPCODE (opcode))
{
flags = cbc_flags[opcode];
#ifdef PARSER_DUMP_BYTE_CODE
name = cbc_names[opcode];
#endif /* PARSER_DUMP_BYTE_CODE */
}
else
{
PARSER_APPEND_TO_BYTE_CODE (context_p, CBC_EXT_OPCODE);
opcode = (uint16_t) PARSER_GET_EXT_OPCODE (opcode);
flags = cbc_ext_flags[opcode];
context_p->byte_code_size++;
#ifdef PARSER_DUMP_BYTE_CODE
name = cbc_ext_names[opcode];
#endif /* PARSER_DUMP_BYTE_CODE */
}
JERRY_ASSERT (flags & CBC_HAS_BRANCH_ARG);
JERRY_ASSERT (CBC_BRANCH_IS_BACKWARD (flags));
JERRY_ASSERT (CBC_BRANCH_OFFSET_LENGTH (opcode) == 1);
JERRY_ASSERT (offset <= context_p->byte_code_size);
/* Branch opcodes never push anything onto the stack. */
JERRY_ASSERT ((flags >> CBC_STACK_ADJUST_SHIFT) >= CBC_STACK_ADJUST_BASE
|| (CBC_STACK_ADJUST_BASE - (flags >> CBC_STACK_ADJUST_SHIFT)) <= context_p->stack_depth);
PARSER_PLUS_EQUAL_U16 (context_p->stack_depth, CBC_STACK_ADJUST_VALUE (flags));
#ifdef PARSER_DUMP_BYTE_CODE
if (context_p->is_show_opcodes)
{
printf (" [%3d] %s\n", (int) context_p->stack_depth, name);
}
#endif /* PARSER_DUMP_BYTE_CODE */
context_p->byte_code_size += 2;
#if PARSER_MAXIMUM_CODE_SIZE <= 65535
if (offset > 255)
{
opcode++;
context_p->byte_code_size++;
}
#else /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
if (offset > 65535)
{
PARSER_PLUS_EQUAL_U16 (opcode, 2);
context_p->byte_code_size += 2;
}
else if (offset > 255)
{
opcode++;
context_p->byte_code_size++;
}
#endif /* PARSER_MAXIMUM_CODE_SIZE <= 65535 */
PARSER_APPEND_TO_BYTE_CODE (context_p, (uint8_t) opcode);
#if PARSER_MAXIMUM_CODE_SIZE > 65535
if (offset > 65535)
{
PARSER_APPEND_TO_BYTE_CODE (context_p, offset >> 16);
}
#endif /* PARSER_MAXIMUM_CODE_SIZE > 65535 */
if (offset > 255)
{
PARSER_APPEND_TO_BYTE_CODE (context_p, (offset >> 8) & 0xff);
}
PARSER_APPEND_TO_BYTE_CODE (context_p, offset & 0xff);
} /* parser_emit_cbc_backward_branch */
#undef PARSER_CHECK_LAST_POSITION
#undef PARSER_APPEND_TO_BYTE_CODE
/**
* Set a branch to the current byte code position
*/
void
parser_set_branch_to_current_position (parser_context_t *context_p, /**< context */
parser_branch_t *branch_p) /**< branch result */
{
uint32_t delta;
size_t offset;
parser_mem_page_t *page_p = branch_p->page_p;
if (context_p->last_cbc_opcode != PARSER_CBC_UNAVAILABLE)
{
parser_flush_cbc (context_p);
}
context_p->status_flags &= ~PARSER_NO_END_LABEL;
JERRY_ASSERT (context_p->byte_code_size > (branch_p->offset >> 8));
delta = context_p->byte_code_size - (branch_p->offset >> 8);
offset = (branch_p->offset & CBC_LOWER_SEVEN_BIT_MASK);
JERRY_ASSERT (delta <= PARSER_MAXIMUM_CODE_SIZE);
#if PARSER_MAXIMUM_CODE_SIZE <= 65535
page_p->bytes[offset++] = (uint8_t) (delta >> 8);
if (offset >= PARSER_CBC_STREAM_PAGE_SIZE)
{
page_p = page_p->next_p;
offset = 0;
}
#else
page_p->bytes[offset++] = (uint8_t) (delta >> 16);
if (offset >= PARSER_CBC_STREAM_PAGE_SIZE)
{
page_p = page_p->next_p;
offset = 0;
}
page_p->bytes[offset++] = (uint8_t) ((delta >> 8) & 0xff);
if (offset >= PARSER_CBC_STREAM_PAGE_SIZE)
{
page_p = page_p->next_p;
offset = 0;
}
#endif
page_p->bytes[offset++] = delta & 0xff;
} /* parser_set_branch_to_current_position */
/**
* Set breaks to the current byte code position
*/
void
parser_set_breaks_to_current_position (parser_context_t *context_p, /**< context */
parser_branch_node_t *current_p) /**< branch list */
{
while (current_p != NULL)
{
parser_branch_node_t *next_p = current_p->next_p;
if (!(current_p->branch.offset & CBC_HIGHEST_BIT_MASK))
{
parser_set_branch_to_current_position (context_p, &current_p->branch);
}
parser_free (current_p);
current_p = next_p;
}
} /* parser_set_breaks_to_current_position */
/**
* Set continues to the current byte code position
*/
void
parser_set_continues_to_current_position (parser_context_t *context_p, /**< context */
parser_branch_node_t *current_p) /**< branch list */
{
while (current_p != NULL)
{
if (current_p->branch.offset & CBC_HIGHEST_BIT_MASK)
{
parser_set_branch_to_current_position (context_p, &current_p->branch);
}
current_p = current_p->next_p;
}
} /* parser_set_continues_to_current_position */
/**
* Returns with the striong representation of the error
*/
const char *
parser_error_to_string (parser_error_t error) /**< error code */
{
switch (error)
{
case PARSER_ERR_OUT_OF_MEMORY:
{
return "Out of memory.";
}
case PARSER_ERR_LITERAL_LIMIT_REACHED:
{
return "Maximum number of literals reached.";
}
case PARSER_ERR_ARGUMENT_LIMIT_REACHED:
{
return "Maximum number of function arguments reached.";
}
case PARSER_ERR_STACK_LIMIT_REACHED:
{
return "Maximum function stack size reached.";
}
case PARSER_ERR_REGISTER_LIMIT_REACHED:
{
return "Maximum number of registers is reached.";
}
case PARSER_ERR_INVALID_CHARACTER:
{
return "Invalid (unexpected) character.";
}
case PARSER_ERR_INVALID_HEX_DIGIT:
{
return "Invalid hexadecimal digit.";
}
case PARSER_ERR_INVALID_ESCAPE_SEQUENCE:
{
return "Invalid escape sequence.";
}
case PARSER_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE:
{
return "Invalid unicode escape sequence.";
}
case PARSER_ERR_INVALID_IDENTIFIER_START:
{
return "Character cannot be start of an identifier.";
}
case PARSER_ERR_INVALID_IDENTIFIER_PART:
{
return "Character cannot be part of an identifier.";
}
case PARSER_ERR_INVALID_NUMBER:
{
return "Invalid number.";
}
case PARSER_ERR_MISSING_EXPONENT:
{
return "Missing exponent part.";
}
case PARSER_ERR_IDENTIFIER_AFTER_NUMBER:
{
return "Identifier cannot start after a number.";
}
case PARSER_ERR_INVALID_REGEXP:
{
return "Invalid regular expression.";
}
case PARSER_ERR_UNKNOWN_REGEXP_FLAG:
{
return "Unknown regexp flag.";
}
case PARSER_ERR_DUPLICATED_REGEXP_FLAG:
{
return "Duplicated regexp flag.";
}
case PARSER_ERR_UNSUPPORTED_REGEXP:
{
return "Regexp is not supported in compact profile.";
}
case PARSER_ERR_IDENTIFIER_TOO_LONG:
{
return "Identifier is too long.";
}
case PARSER_ERR_STRING_TOO_LONG:
{
return "String is too long.";
}
case PARSER_ERR_NUMBER_TOO_LONG:
{
return "Number too long.";
}
case PARSER_ERR_REGEXP_TOO_LONG:
{
return "Regexp too long.";
}
case PARSER_ERR_UNTERMINATED_MULTILINE_COMMENT:
{
return "Unterminated multiline comment.";
}
case PARSER_ERR_UNTERMINATED_STRING:
{
return "Unterminated string literal.";
}
case PARSER_ERR_UNTERMINATED_REGEXP:
{
return "Unterminated regexp literal.";
}
case PARSER_ERR_NEWLINE_NOT_ALLOWED:
{
return "Newline is not allowed in strings or regexps.";
}
case PARSER_ERR_OCTAL_NUMBER_NOT_ALLOWED:
{
return "Octal numbers are not allowed in strict mode.";
}
case PARSER_ERR_OCTAL_ESCAPE_NOT_ALLOWED:
{
return "Octal escape sequences are not allowed in strict mode.";
}
case PARSER_ERR_STRICT_IDENT_NOT_ALLOWED:
{
return "Identifier name is reserved in strict mode.";
}
case PARSER_ERR_EVAL_NOT_ALLOWED:
{
return "Eval is not allowed to use here in strict mode.";
}
case PARSER_ERR_ARGUMENTS_NOT_ALLOWED:
{
return "Arguments is not allowed to use here in strict mode.";
}
case PARSER_ERR_DELETE_IDENT_NOT_ALLOWED:
{
return "Deleting identifier is not allowed in strict mode.";
}
case PARSER_ERR_EVAL_CANNOT_ASSIGNED:
{
return "Eval cannot assigned in strict mode.";
}
case PARSER_ERR_ARGUMENTS_CANNOT_ASSIGNED:
{
return "Arguments cannot assigned in strict mode.";
}
case PARSER_ERR_WITH_NOT_ALLOWED:
{
return "With statement not allowed in strict mode.";
}
case PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED:
{
return "Multiple default cases not allowed.";
}
case PARSER_ERR_DEFAULT_NOT_IN_SWITCH:
{
return "Default statement must be in a switch block.";
}
case PARSER_ERR_CASE_NOT_IN_SWITCH:
{
return "Case statement must be in a switch block.";
}
case PARSER_ERR_LEFT_PAREN_EXPECTED:
{
return "Expected '(' token.";
}
case PARSER_ERR_LEFT_BRACE_EXPECTED:
{
return "Expected '{' token.";
}
case PARSER_ERR_RIGHT_PAREN_EXPECTED:
{
return "Expected ')' token.";
}
case PARSER_ERR_RIGHT_SQUARE_EXPECTED:
{
return "Expected ']' token.";
}
case PARSER_ERR_COLON_EXPECTED:
{
return "Expected ':' token.";
}
case PARSER_ERR_COLON_FOR_CONDITIONAL_EXPECTED:
{
return "Expected ':' token for ?: conditional expression.";
}
case PARSER_ERR_SEMICOLON_EXPECTED:
{
return "Expected ';' token.";
}
case PARSER_ERR_IN_EXPECTED:
{
return "Expected 'in' token.";
}
case PARSER_ERR_WHILE_EXPECTED:
{
return "While expected for do-while loop.";
}
case PARSER_ERR_CATCH_FINALLY_EXPECTED:
{
return "Catch or finally block expected.";
}
case PARSER_ERR_ARRAY_ITEM_SEPARATOR_EXPECTED:
{
return "Expected ',' or ']' after an array item.";
}
case PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED:
{
return "Expected ',' or '}' after a property definition.";
}
case PARSER_ERR_IDENTIFIER_EXPECTED:
{
return "Identifier expected.";
}
case PARSER_ERR_EXPRESSION_EXPECTED:
{
return "Expression expected.";
}
case PARSER_ERR_PRIMARY_EXP_EXPECTED:
{
return "Primary expression expected.";
}
case PARSER_ERR_STATEMENT_EXPECTED:
{
return "Statement expected.";
}
case PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED:
{
return "Property identifier expected.";
}
case PARSER_ERR_ARGUMENT_LIST_EXPECTED:
{
return "Expected argument list.";
}
case PARSER_ERR_NO_ARGUMENTS_EXPECTED:
{
return "Property getters must have no arguments.";
}
case PARSER_ERR_ONE_ARGUMENT_EXPECTED:
{
return "Property setters must have one argument.";
}
case PARSER_ERR_INVALID_EXPRESSION:
{
return "Invalid expression.";
}
case PARSER_ERR_INVALID_SWITCH:
{
return "Invalid switch body.";
}
case PARSER_ERR_INVALID_BREAK:
{
return "Break statement must be inside a loop or switch.";
}
case PARSER_ERR_INVALID_BREAK_LABEL:
{
return "Labelled statement targeted by a break not found.";
}
case PARSER_ERR_INVALID_CONTINUE:
{
return "Continue statement must be inside a loop.";
}
case PARSER_ERR_INVALID_CONTINUE_LABEL:
{
return "Labelled statement targeted by a continue noty found.";
}
case PARSER_ERR_INVALID_RETURN:
{
return "Return statement must be inside a function body.";
}
case PARSER_ERR_INVALID_RIGHT_SQUARE:
{
return "Unexpected '}' token.";
}
case PARSER_ERR_DUPLICATED_LABEL:
{
return "Duplicated label.";
}
case PARSER_ERR_OBJECT_PROPERTY_REDEFINED:
{
return "Property of object literal redefined.";
}
case PARSER_ERR_NON_STRICT_ARG_DEFINITION:
{
return "Non strict argument definition.";
}
default:
{
break;
}
}
JERRY_ASSERT (error == PARSER_ERR_NO_ERROR);
return "No error.";
} /* parser_error_to_string */
/**
* @}
* @}
* @}
*/
File diff suppressed because it is too large Load Diff
+143
View File
@@ -0,0 +1,143 @@
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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 JS_PARSER_H
#define JS_PARSER_H
#include "byte-code.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser JavaScript
* @{
*
* \addtogroup jsparser_parser Parser
* @{
*/
/**
* Error codes.
*/
typedef enum
{
PARSER_ERR_NO_ERROR, /**< no error */
PARSER_ERR_OUT_OF_MEMORY, /**< out of memory */
PARSER_ERR_LITERAL_LIMIT_REACHED, /**< maximum number of literals reached */
PARSER_ERR_ARGUMENT_LIMIT_REACHED, /**< maximum number of function arguments reached */
PARSER_ERR_STACK_LIMIT_REACHED, /**< maximum function stack size reached */
PARSER_ERR_REGISTER_LIMIT_REACHED, /**< maximum register size reached */
PARSER_ERR_INVALID_CHARACTER, /**< unexpected character */
PARSER_ERR_INVALID_HEX_DIGIT, /**< invalid hexadecimal digit */
PARSER_ERR_INVALID_ESCAPE_SEQUENCE, /**< invalid escape sequence */
PARSER_ERR_INVALID_UNICODE_ESCAPE_SEQUENCE, /**< invalid unicode escape sequence */
PARSER_ERR_INVALID_IDENTIFIER_START, /**< character cannot be start of an identifier */
PARSER_ERR_INVALID_IDENTIFIER_PART, /**< character cannot be part of an identifier */
PARSER_ERR_INVALID_NUMBER, /**< invalid number literal */
PARSER_ERR_MISSING_EXPONENT, /**< missing exponent */
PARSER_ERR_IDENTIFIER_AFTER_NUMBER, /**< identifier start after number */
PARSER_ERR_INVALID_REGEXP, /**< invalid regular expression */
PARSER_ERR_UNKNOWN_REGEXP_FLAG, /**< unknown regexp flag */
PARSER_ERR_DUPLICATED_REGEXP_FLAG, /**< duplicated regexp flag */
PARSER_ERR_UNSUPPORTED_REGEXP, /**< regular expression is not supported in compact profile */
PARSER_ERR_IDENTIFIER_TOO_LONG, /**< too long identifier */
PARSER_ERR_STRING_TOO_LONG, /**< too long string literal */
PARSER_ERR_NUMBER_TOO_LONG, /**< too long number literal */
PARSER_ERR_REGEXP_TOO_LONG, /**< too long regexp literal */
PARSER_ERR_UNTERMINATED_MULTILINE_COMMENT, /**< unterminated multiline comment */
PARSER_ERR_UNTERMINATED_STRING, /**< unterminated string literal */
PARSER_ERR_UNTERMINATED_REGEXP, /**< unterminated regexp literal */
PARSER_ERR_NEWLINE_NOT_ALLOWED, /**< newline is not allowed */
PARSER_ERR_OCTAL_NUMBER_NOT_ALLOWED, /**< octal numbers are not allowed in strict mode */
PARSER_ERR_OCTAL_ESCAPE_NOT_ALLOWED, /**< octal escape sequences are not allowed in strict mode */
PARSER_ERR_STRICT_IDENT_NOT_ALLOWED, /**< identifier name is reserved in strict mode */
PARSER_ERR_EVAL_NOT_ALLOWED, /**< eval is not allowed here in strict mode */
PARSER_ERR_ARGUMENTS_NOT_ALLOWED, /**< arguments is not allowed here in strict mode */
PARSER_ERR_DELETE_IDENT_NOT_ALLOWED, /**< identifier delete is not allowed in strict mode */
PARSER_ERR_EVAL_CANNOT_ASSIGNED, /**< eval cannot be assigned in strict mode */
PARSER_ERR_ARGUMENTS_CANNOT_ASSIGNED, /**< arguments cannot be assigned in strict mode */
PARSER_ERR_WITH_NOT_ALLOWED, /**< with statement is not allowed in strict mode */
PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED, /**< multiple default cases are not allowed */
PARSER_ERR_DEFAULT_NOT_IN_SWITCH, /**< default statement is not in switch block */
PARSER_ERR_CASE_NOT_IN_SWITCH, /**< case statement is not in switch block */
PARSER_ERR_LEFT_PAREN_EXPECTED, /**< left paren expected */
PARSER_ERR_LEFT_BRACE_EXPECTED, /**< left brace expected */
PARSER_ERR_RIGHT_PAREN_EXPECTED, /**< right paren expected */
PARSER_ERR_RIGHT_SQUARE_EXPECTED, /**< right square expected */
PARSER_ERR_COLON_EXPECTED, /**< colon expected */
PARSER_ERR_COLON_FOR_CONDITIONAL_EXPECTED, /**< colon expected for conditional expression */
PARSER_ERR_SEMICOLON_EXPECTED, /**< semicolon expected */
PARSER_ERR_IN_EXPECTED, /**< in keyword expected */
PARSER_ERR_WHILE_EXPECTED, /**< while expected for do-while loop */
PARSER_ERR_CATCH_FINALLY_EXPECTED, /**< catch or finally expected */
PARSER_ERR_ARRAY_ITEM_SEPARATOR_EXPECTED, /**< array item separator expected */
PARSER_ERR_OBJECT_ITEM_SEPARATOR_EXPECTED, /**< object item separator expected */
PARSER_ERR_IDENTIFIER_EXPECTED, /**< identifier expected */
PARSER_ERR_EXPRESSION_EXPECTED, /**< expression expected */
PARSER_ERR_PRIMARY_EXP_EXPECTED, /**< primary expression expected */
PARSER_ERR_STATEMENT_EXPECTED, /**< statement expected */
PARSER_ERR_PROPERTY_IDENTIFIER_EXPECTED, /**< property identifier expected */
PARSER_ERR_ARGUMENT_LIST_EXPECTED, /**< argument list expected */
PARSER_ERR_NO_ARGUMENTS_EXPECTED, /**< property getters must have no arguments */
PARSER_ERR_ONE_ARGUMENT_EXPECTED, /**< property setters must have one argument */
PARSER_ERR_INVALID_EXPRESSION, /**< invalid expression */
PARSER_ERR_INVALID_SWITCH, /**< invalid switch body */
PARSER_ERR_INVALID_BREAK, /**< break must be inside a loop or switch */
PARSER_ERR_INVALID_BREAK_LABEL, /**< break target not found */
PARSER_ERR_INVALID_CONTINUE, /**< continue must be inside a loop */
PARSER_ERR_INVALID_CONTINUE_LABEL, /**< continue target not found */
PARSER_ERR_INVALID_RETURN, /**< return must be inside a function */
PARSER_ERR_INVALID_RIGHT_SQUARE, /**< right square must terminate a block */
PARSER_ERR_DUPLICATED_LABEL, /**< duplicated label */
PARSER_ERR_OBJECT_PROPERTY_REDEFINED, /**< property of object literal redefined */
PARSER_ERR_NON_STRICT_ARG_DEFINITION /**< non-strict argument definition */
} parser_error_t;
/* Source code line counter type. */
typedef uint32_t parser_line_counter_t;
/**
* Error code location.
*/
typedef struct
{
parser_error_t error; /**< error code */
parser_line_counter_t line; /**< line where the error occured */
parser_line_counter_t column; /**< column where the error occured */
} parser_error_location;
/* Note: source must be a valid UTF-8 string. */
ecma_compiled_code_t * parser_parse_script (const uint8_t *, size_t, int, parser_error_location *);
const char *parser_error_to_string (parser_error_t);
extern void parser_set_show_instrs (int);
/**
* @}
* @}
* @}
*/
#endif /* !JS_PARSER_H */
-255
View File
@@ -1,255 +0,0 @@
/* Copyright 2014-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 "jsp-early-error.h"
#include "stack.h"
#include "jrt.h"
#include "parser.h"
#include "jrt-libc-includes.h"
#include "ecma-helpers.h"
#include "lit-magic-strings.h"
/**
* Early error longjmp label, used to finish parse upon an early error occurence
*
* See also:
* jsp_early_error_get_early_error_longjmp_label
* jsp_early_error_raise_error
*/
static jmp_buf jsp_early_error_label;
/**
* Type of early error occured, or JSP_EARLY_ERROR__NO_ERROR
*/
jsp_early_error_t jsp_early_error_type;
typedef struct
{
prop_type type;
lit_literal_t lit;
} prop_literal;
enum
{
props_global_size
};
STATIC_STACK (props, prop_literal)
enum
{
size_t_stack_global_size
};
STATIC_STACK (size_t_stack, size_t)
/**
* Get buffer for SyntaxError longjmp label
*
* @return pointer to jmp_buf
*/
jmp_buf *
jsp_early_error_get_early_error_longjmp_label (void)
{
return &jsp_early_error_label;
} /* jsp_early_error_get_early_error_longjmp_label */
/**
* Raise an early error of specified type
*
* Note:
* Performs longjmp to early error longjmp label
*
* See also:
* parser_parse_program
*/
void __attribute__((noreturn))
jsp_early_error_raise_error (jsp_early_error_t type) /**< type of error to raise */
{
JERRY_ASSERT (jsp_early_error_type == JSP_EARLY_ERROR__NO_ERROR);
jsp_early_error_type = type;
longjmp (jsp_early_error_label, 1);
} /* jsp_early_error_raise_error */
/**
* Get type of occured early error
*
* @return type
*/
jsp_early_error_t
jsp_early_error_get_type (void)
{
JERRY_ASSERT (jsp_early_error_type != JSP_EARLY_ERROR__NO_ERROR);
return jsp_early_error_type;
} /* jsp_early_error_get_type */
static prop_literal
create_prop_literal (lit_literal_t lit, prop_type type)
{
prop_literal ret;
ret.type = type;
ret.lit = lit;
return ret;
}
void
jsp_early_error_start_checking_of_prop_names (void)
{
STACK_PUSH (size_t_stack, STACK_SIZE (props));
}
void
jsp_early_error_add_prop_name (jsp_operand_t op, prop_type pt)
{
JERRY_ASSERT (jsp_is_string_lit_operand (op));
STACK_PUSH (props, create_prop_literal (lit_get_literal_by_cp (jsp_operand_get_literal (op)), pt));
}
void
jsp_early_error_check_for_duplication_of_prop_names (bool is_strict, locus loc __attr_unused___)
{
if (STACK_SIZE (props) - STACK_TOP (size_t_stack) < 2)
{
STACK_DROP (props, (size_t) (STACK_SIZE (props) - STACK_TOP (size_t_stack)));
STACK_DROP (size_t_stack, 1);
return;
}
for (size_t i = (STACK_TOP (size_t_stack) + 1);
i < STACK_SIZE (props);
i++)
{
const prop_literal previous = STACK_ELEMENT (props, i);
JERRY_ASSERT (previous.type == PROP_DATA
|| previous.type == PROP_GET
|| previous.type == PROP_SET);
for (size_t j = STACK_TOP (size_t_stack); j < i; j = j + 1)
{
/*4*/
const prop_literal current = STACK_ELEMENT (props, j);
JERRY_ASSERT (current.type == PROP_DATA
|| current.type == PROP_GET
|| current.type == PROP_SET);
if (lit_literal_equal (previous.lit, current.lit))
{
/*a*/
if (is_strict && previous.type == PROP_DATA && current.type == PROP_DATA)
{
PARSE_ERROR_VARG (JSP_EARLY_ERROR_SYNTAX,
"Duplication of parameter name '%s' in ObjectDeclaration is not allowed in strict mode",
loc, lit_literal_to_str_internal_buf (current.lit));
}
/*b*/
if (previous.type == PROP_DATA
&& (current.type == PROP_SET || current.type == PROP_GET))
{
PARSE_ERROR_VARG (JSP_EARLY_ERROR_SYNTAX,
"Parameter name '%s' in ObjectDeclaration may not be both data and accessor",
loc, lit_literal_to_str_internal_buf (current.lit));
}
/*c*/
if (current.type == PROP_DATA
&& (previous.type == PROP_SET || previous.type == PROP_GET))
{
PARSE_ERROR_VARG (JSP_EARLY_ERROR_SYNTAX,
"Parameter name '%s' in ObjectDeclaration may not be both data and accessor",
loc, lit_literal_to_str_internal_buf (current.lit));
}
/*d*/
if ((previous.type == PROP_SET && current.type == PROP_SET)
|| (previous.type == PROP_GET && current.type == PROP_GET))
{
PARSE_ERROR_VARG (JSP_EARLY_ERROR_SYNTAX,
"Parameter name '%s' in ObjectDeclaration may not be accessor of same type",
loc, lit_literal_to_str_internal_buf (current.lit));
}
}
}
}
STACK_DROP (props, (size_t) (STACK_SIZE (props) - STACK_TOP (size_t_stack)));
STACK_DROP (size_t_stack, 1);
}
void
jsp_early_error_emit_error_on_eval_and_arguments (lit_literal_t lit, /**< literal to check */
locus loc) /**< location of the literal in source code */
{
if (lit_literal_equal_type_utf8 (lit,
lit_get_magic_string_utf8 (LIT_MAGIC_STRING_ARGUMENTS),
lit_get_magic_string_size (LIT_MAGIC_STRING_ARGUMENTS))
|| lit_literal_equal_type_utf8 (lit,
lit_get_magic_string_utf8 (LIT_MAGIC_STRING_EVAL),
lit_get_magic_string_size (LIT_MAGIC_STRING_EVAL)))
{
PARSE_ERROR (JSP_EARLY_ERROR_SYNTAX, "'eval' and 'arguments' are not allowed here in strict mode", loc);
}
}
void
jsp_early_error_check_for_eval_and_arguments_in_strict_mode (jsp_operand_t op, bool is_strict, locus loc)
{
if (is_strict)
{
lit_cpointer_t lit_cp;
if (jsp_is_string_lit_operand (op)
|| jsp_is_number_lit_operand (op))
{
lit_cp = jsp_operand_get_literal (op);
}
else if (jsp_is_identifier_operand (op))
{
lit_cp = jsp_operand_get_identifier_name (op);
}
else
{
return;
}
jsp_early_error_emit_error_on_eval_and_arguments (lit_get_literal_by_cp (lit_cp), loc);
}
}
void
jsp_early_error_check_delete (bool is_strict, locus loc __attr_unused___)
{
if (is_strict)
{
PARSE_ERROR (JSP_EARLY_ERROR_SYNTAX, "'delete' operator shall not apply on identifier in strict mode.", loc);
}
}
void
jsp_early_error_init (void)
{
jsp_early_error_type = JSP_EARLY_ERROR__NO_ERROR;
STACK_INIT (props);
STACK_INIT (size_t_stack);
}
void
jsp_early_error_free (void)
{
STACK_FREE (size_t_stack);
STACK_FREE (props);
}
-90
View File
@@ -1,90 +0,0 @@
/* Copyright 2014-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 JSP_EARLY_ERROR_H
#define JSP_EARLY_ERROR_H
#include "jrt-libc-includes.h"
#include "lexer.h"
#include "opcodes-dumper.h"
#ifndef JERRY_NDEBUG
#define PARSE_ERROR_PRINT_PLACE(TYPE, LOCUS) do { \
size_t line, column; \
lexer_locus_to_line_and_column ((LOCUS), &line, &column); \
lexer_dump_line (line); \
printf ("\n"); \
for (size_t i = 0; i < column; i++) { \
jerry_port_putchar (' '); \
} \
printf ("^\n"); \
printf ("%s: Ln %lu, Col %lu: ", TYPE, (unsigned long) (line + 1), (unsigned long) (column + 1)); \
} while (0)
#define PARSE_ERROR(type, MESSAGE, LOCUS) do { \
locus __loc = LOCUS; \
PARSE_ERROR_PRINT_PLACE ("ERROR", __loc); \
printf ("%s\n", MESSAGE); \
jsp_early_error_raise_error (type); \
} while (0)
#define PARSE_ERROR_VARG(type, MESSAGE, LOCUS, ...) do { \
locus __loc = LOCUS; \
PARSE_ERROR_PRINT_PLACE ("ERROR", __loc); \
printf (MESSAGE, __VA_ARGS__); \
printf ("\n"); \
jsp_early_error_raise_error (type); \
} while (0)
#else /* JERRY_NDEBUG */
#define PARSE_ERROR(type, MESSAGE, LOCUS) do { \
locus __attr_unused___ unused_value = LOCUS; jsp_early_error_raise_error (type); \
} while (0)
#define PARSE_ERROR_VARG(type, MESSAGE, LOCUS, ...) do { \
locus __attr_unused___ unused_value = LOCUS; jsp_early_error_raise_error (type); \
} while (0)
#endif /* JERRY_NDEBUG */
typedef enum __attr_packed___
{
PROP_DATA,
PROP_SET,
PROP_GET
} prop_type;
/**
* Early error types (ECMA-262 v5, 16)
*/
typedef enum
{
JSP_EARLY_ERROR__NO_ERROR, /** initializer value (indicates that no error occured) */
JSP_EARLY_ERROR_SYNTAX, /**< SyntaxError */
JSP_EARLY_ERROR_REFERENCE /**< ReferenceError */
} jsp_early_error_t;
void jsp_early_error_init (void);
void jsp_early_error_free (void);
void jsp_early_error_start_checking_of_prop_names (void);
void jsp_early_error_add_prop_name (jsp_operand_t, prop_type);
void jsp_early_error_check_for_duplication_of_prop_names (bool, locus);
void jsp_early_error_emit_error_on_eval_and_arguments (lit_literal_t, locus);
void jsp_early_error_check_for_eval_and_arguments_in_strict_mode (jsp_operand_t, bool, locus);
void jsp_early_error_check_delete (bool, locus);
jmp_buf *jsp_early_error_get_early_error_longjmp_label (void);
void __attribute__((noreturn)) jsp_early_error_raise_error (jsp_early_error_t);
jsp_early_error_t jsp_early_error_get_type (void);
#endif /* JSP_EARLY_ERROR_H */
-122
View File
@@ -1,122 +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 JSP_INTERNAL_H
#define JSP_INTERNAL_H
#include "scopes-tree.h"
/**
* Parse stage
*/
typedef enum
{
PREPARSE, /**< preparse stage */
DUMP /**< dump stage */
} jsp_parse_mode_t;
/**
* Size of the temporary literal set
*/
#define SCOPE_TMP_LIT_SET_SIZE 32
/**
* Parser context
*/
typedef struct
{
struct jsp_state_t *state_stack_p; /**< parser stack */
jsp_parse_mode_t mode; /**< parse stage */
scope_type_t scope_type; /**< type of currently parsed scope */
uint16_t processed_child_scopes_counter; /**< number of processed
* child scopes of the
* current scope */
union
{
/**
* Preparse stage information
*/
struct
{
/**
* Currently parsed scope
*/
scopes_tree current_scope_p;
/**
* Container of the temporary literal set
*
* Temporary literal set is used for estimation of number of unique literals
* in a byte-code instructions block (BLOCK_SIZE). The calculated number
* is always equal or larger than actual number of unique literals.
*
* The set is emptied upon:
* - reaching a bytecode block border;
* - changing scope, to which instructions are dumped.
*
* Emptying the set in second case is necessary, as the set should contain
* unique literals of a bytecode block, and, upon switching to another scope,
* current bytecode block is also switched, correspondingly. However, this
* could only lead to overestimation of unique literals number, relatively
* to the actual number.
*/
lit_cpointer_t tmp_lit_set[SCOPE_TMP_LIT_SET_SIZE];
/**
* Number of items in the temporary literal set
*/
uint8_t tmp_lit_set_num;
} preparse_stage;
/**
* Dump stage information
*/
struct
{
/**
* Current scope's byte-code header
*/
bytecode_data_header_t *current_bc_header_p;
/**
* Pointer to the scope that would be parsed next
*/
scopes_tree next_scope_to_dump_p;
} dump_stage;
} u;
} jsp_ctx_t;
void jsp_init_ctx (jsp_ctx_t *, scope_type_t);
bool jsp_is_dump_mode (jsp_ctx_t *);
void jsp_switch_to_dump_mode (jsp_ctx_t *, scopes_tree);
bool jsp_is_strict_mode (jsp_ctx_t *);
void jsp_set_strict_mode (jsp_ctx_t *);
scope_type_t jsp_get_scope_type (jsp_ctx_t *);
void jsp_set_scope_type (jsp_ctx_t *, scope_type_t);
uint16_t jsp_get_processed_child_scopes_counter (jsp_ctx_t *);
void jsp_set_processed_child_scopes_counter (jsp_ctx_t *, uint16_t);
uint16_t jsp_get_and_inc_processed_child_scopes_counter (jsp_ctx_t *);
scopes_tree jsp_get_next_scopes_tree_node_to_dump (jsp_ctx_t *);
scopes_tree jsp_get_current_scopes_tree_node (jsp_ctx_t *);
void jsp_set_current_scopes_tree_node (jsp_ctx_t *, scopes_tree);
bytecode_data_header_t *jsp_get_current_bytecode_header (jsp_ctx_t *);
void jsp_set_current_bytecode_header (jsp_ctx_t *, bytecode_data_header_t *);
void jsp_empty_tmp_literal_set (jsp_ctx_t *);
void jsp_account_next_bytecode_to_literal_reference (jsp_ctx_t *, lit_cpointer_t);
#endif /* !JSP_INTERNAL_H */
-170
View File
@@ -1,170 +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 "jrt.h"
#include "jsp-mm.h"
#include "mem-allocator.h"
#include "mem-heap.h"
/** \addtogroup jsparser ECMAScript parser
* @{
*
* \addtogroup managedmem Managed memory allocation
* @{
*/
/**
* Header of a managed block, allocated by parser
*/
typedef struct
{
mem_cpointer_t prev_block_cp; /**< previous managed block */
mem_cpointer_t next_block_cp; /**< next managed block */
uint32_t padding; /**< padding for alignment */
} jsp_mm_header_t;
/**
* Check that alignment of jsp_mm_header_t is MEM_ALIGNMENT
*/
JERRY_STATIC_ASSERT ((sizeof (jsp_mm_header_t) % MEM_ALIGNMENT) == 0);
/**
* List used for tracking memory blocks
*/
jsp_mm_header_t *jsp_mm_blocks_p = NULL;
/**
* Initialize managed memory allocator
*/
void
jsp_mm_init (void)
{
JERRY_ASSERT (jsp_mm_blocks_p == NULL);
} /* jsp_mm_init */
/**
* Finalize managed memory allocator
*/
void
jsp_mm_finalize (void)
{
JERRY_ASSERT (jsp_mm_blocks_p == NULL);
} /* jsp_mm_finalize */
/**
* Recommend allocation size
*
* Note:
* The interface is used by collection allocators
* for storage of data that takes the specified
* amount of bytes upon allocation, but probably
* would require more.
*
* To reduce probability of reallocation in future,
* the allocators can request more space in first
* allocation request.
*
* The interface helps to choose appropriate space
* to allocate, considering amount of heap space,
* that would be waste if allocation size
* would not be increased.
*
* @return recommended allocation size
*/
size_t
jsp_mm_recommend_size (size_t minimum_size) /**< minimum required size */
{
size_t block_and_header_size = mem_heap_recommend_allocation_size (minimum_size + sizeof (jsp_mm_header_t));
return block_and_header_size - sizeof (jsp_mm_header_t);
} /* jsp_mm_recommend_size */
/**
* Allocate a managed memory block of specified size
*
* @return pointer to data space of allocated block
*/
void*
jsp_mm_alloc (size_t size) /**< size of block to allocate */
{
void *ptr_p = mem_heap_alloc_block (size + sizeof (jsp_mm_header_t), MEM_HEAP_ALLOC_SHORT_TERM);
jsp_mm_header_t *tmem_header_p = (jsp_mm_header_t*) ptr_p;
tmem_header_p->prev_block_cp = MEM_CP_NULL;
MEM_CP_SET_POINTER (tmem_header_p->next_block_cp, jsp_mm_blocks_p);
if (jsp_mm_blocks_p != NULL)
{
MEM_CP_SET_POINTER (jsp_mm_blocks_p->prev_block_cp, tmem_header_p);
}
jsp_mm_blocks_p = tmem_header_p;
return (void *) (tmem_header_p + 1);
} /* jsp_mm_alloc */
/**
* Free a managed memory block
*/
void
jsp_mm_free (void *ptr) /**< pointer to data space of allocated block */
{
jsp_mm_header_t *tmem_header_p = ((jsp_mm_header_t *) ptr) - 1;
jsp_mm_header_t *prev_block_p = MEM_CP_GET_POINTER (jsp_mm_header_t,
tmem_header_p->prev_block_cp);
jsp_mm_header_t *next_block_p = MEM_CP_GET_POINTER (jsp_mm_header_t,
tmem_header_p->next_block_cp);
if (prev_block_p != NULL)
{
prev_block_p->next_block_cp = tmem_header_p->next_block_cp;
}
else
{
JERRY_ASSERT (jsp_mm_blocks_p == tmem_header_p);
jsp_mm_blocks_p = next_block_p;
}
if (next_block_p != NULL)
{
next_block_p->prev_block_cp = tmem_header_p->prev_block_cp;
}
mem_heap_free_block (tmem_header_p);
} /* jsp_mm_free */
/**
* Free all currently allocated managed memory blocks
*/
void
jsp_mm_free_all (void)
{
while (jsp_mm_blocks_p != NULL)
{
jsp_mm_header_t *next_block_p = MEM_CP_GET_POINTER (jsp_mm_header_t,
jsp_mm_blocks_p->next_block_cp);
mem_heap_free_block (jsp_mm_blocks_p);
jsp_mm_blocks_p = next_block_p;
}
} /* jsp_mm_free_all */
/**
* @}
* @}
*/
-40
View File
@@ -1,40 +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 JSP_MM_H
#define JSP_MM_H
#include "jrt-libc-includes.h"
/** \addtogroup jsparser ECMAScript parser
* @{
*
* \addtogroup managedmem Managed memory allocation
* @{
*/
extern void jsp_mm_init (void);
extern void jsp_mm_finalize (void);
extern size_t jsp_mm_recommend_size (size_t);
extern void *jsp_mm_alloc (size_t);
extern void jsp_mm_free (void *);
extern void jsp_mm_free_all (void);
/**
* @}
* @}
*/
#endif /* !JSP_MM_H */
File diff suppressed because it is too large Load Diff
-282
View File
@@ -1,282 +0,0 @@
/* Copyright 2014-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 LEXER_H
#define LEXER_H
#include "lit-literal.h"
#include "lit-strings.h"
#define INVALID_LITERAL (rcs_cpointer_null_cp ())
/* Keywords. */
typedef enum __attr_packed___
{
/* Not a keyword. */
KW_BREAK,
KW_CASE,
KW_CATCH,
KW_CLASS,
KW_CONST,
KW_CONTINUE,
KW_DEBUGGER,
KW_DEFAULT,
KW_DELETE,
KW_DO,
KW_ELSE,
KW_ENUM,
KW_EXPORT,
KW_EXTENDS,
KW_FINALLY,
KW_FOR,
KW_FUNCTION,
KW_IF,
KW_IN,
KW_INSTANCEOF,
KW_INTERFACE,
KW_IMPORT,
KW_IMPLEMENTS,
KW_LET,
KW_NEW,
KW_PACKAGE,
KW_PRIVATE,
KW_PROTECTED,
KW_PUBLIC,
KW_RETURN,
KW_STATIC,
KW_SUPER,
KW_SWITCH,
KW_THIS,
KW_THROW,
KW_TRY,
KW_TYPEOF,
KW_VAR,
KW_VOID,
KW_WHILE,
KW_WITH,
KW_YIELD
} keyword;
/* Type of tokens. */
typedef enum __attr_packed___
{
TOKEN_TYPE__BEGIN = 1,
TOK_EOF = TOKEN_TYPE__BEGIN, // End of file
TOK_NAME, // Identifier
TOK_SMALL_INT,
TOK_NUMBER,
TOK_NULL,
TOK_BOOL,
TOK_STRING,
TOK_OPEN_BRACE, // {
TOK_CLOSE_BRACE, // }
TOK_OPEN_PAREN, // (
TOK_CLOSE_PAREN, //)
TOK_OPEN_SQUARE, // [
TOK_CLOSE_SQUARE, // ]
TOK_DOT, // .
TOK_SEMICOLON, // ;
TOK_COMMA, // ,
TOKEN_TYPE__UNARY_BEGIN,
TOKEN_TYPE__ADDITIVE_BEGIN = TOKEN_TYPE__UNARY_BEGIN,
TOK_PLUS = TOKEN_TYPE__ADDITIVE_BEGIN, // +
TOK_MINUS, // -
TOKEN_TYPE__ADDITIVE_END = TOK_MINUS,
TOK_DOUBLE_PLUS, // ++
TOK_DOUBLE_MINUS, // --
TOK_NOT, // !
TOK_COMPL, // ~
TOKEN_TYPE__UNARY_END = TOK_COMPL, /* keywords are not listed
* in the range */
TOKEN_TYPE__MULTIPLICATIVE_BEGIN,
TOK_MULT = TOKEN_TYPE__MULTIPLICATIVE_BEGIN, // *
TOK_MOD, // %
TOK_DIV, // /
TOKEN_TYPE__MULTIPLICATIVE_END = TOK_DIV,
TOKEN_TYPE__SHIFT_BEGIN,
TOK_LSHIFT = TOKEN_TYPE__SHIFT_BEGIN, // <<
TOK_RSHIFT, // >>
TOK_RSHIFT_EX, // >>>
TOKEN_TYPE__SHIFT_END = TOK_RSHIFT_EX,
TOKEN_TYPE__RELATIONAL_BEGIN,
TOK_LESS = TOKEN_TYPE__RELATIONAL_BEGIN, // <
TOK_GREATER, // >
TOK_LESS_EQ, // <=
TOK_GREATER_EQ, // <=
TOKEN_TYPE__RELATIONAL_END = TOK_GREATER_EQ,
TOKEN_TYPE__EQUALITY_BEGIN,
TOK_DOUBLE_EQ = TOKEN_TYPE__EQUALITY_BEGIN, // ==
TOK_NOT_EQ, // !=
TOK_TRIPLE_EQ, // ===
TOK_NOT_DOUBLE_EQ, // !==
TOKEN_TYPE__EQUALITY_END = TOK_NOT_DOUBLE_EQ,
TOK_AND, // &
TOK_OR, // |
TOK_XOR, // ^
TOK_DOUBLE_AND, // &&
TOK_DOUBLE_OR, // ||
TOK_QUERY, // ?
TOK_COLON, // :
TOKEN_TYPE__ASSIGNMENTS_BEGIN,
TOK_EQ = TOKEN_TYPE__ASSIGNMENTS_BEGIN, // =
TOK_PLUS_EQ, // +=
TOK_MINUS_EQ, // -=
TOK_MULT_EQ, // *=
TOK_MOD_EQ, // %=
TOK_LSHIFT_EQ, // <<=
TOK_RSHIFT_EQ, // >>=
TOK_RSHIFT_EX_EQ, // >>>=
TOK_AND_EQ, // &=
TOK_OR_EQ, // |=
TOK_XOR_EQ, // ^=
TOK_DIV_EQ, // /=
TOKEN_TYPE__ASSIGNMENTS_END = TOK_DIV_EQ,
TOK_EMPTY,
TOK_REGEXP, // RegularExpressionLiteral (/.../gim)
TOKEN_TYPE__KEYWORD_BEGIN,
TOK_KW_BREAK,
TOK_KW_CASE,
TOK_KW_CATCH,
TOK_KW_CLASS,
TOK_KW_CONST,
TOK_KW_CONTINUE,
TOK_KW_DEBUGGER,
TOK_KW_DEFAULT,
TOK_KW_DELETE,
TOK_KW_DO,
TOK_KW_ELSE,
TOK_KW_ENUM,
TOK_KW_EXPORT,
TOK_KW_EXTENDS,
TOK_KW_FINALLY,
TOK_KW_FOR,
TOK_KW_FUNCTION,
TOK_KW_IF,
TOK_KW_IN,
TOK_KW_INSTANCEOF,
TOK_KW_INTERFACE,
TOK_KW_IMPORT,
TOK_KW_IMPLEMENTS,
TOK_KW_LET,
TOK_KW_NEW,
TOK_KW_PACKAGE,
TOK_KW_PRIVATE,
TOK_KW_PROTECTED,
TOK_KW_PUBLIC,
TOK_KW_RETURN,
TOK_KW_STATIC,
TOK_KW_SUPER,
TOK_KW_SWITCH,
TOK_KW_THIS,
TOK_KW_THROW,
TOK_KW_TRY,
TOK_KW_TYPEOF,
TOK_KW_VAR,
TOK_KW_VOID,
TOK_KW_WHILE,
TOK_KW_WITH,
TOK_KW_YIELD,
TOKEN_TYPE__KEYWORD_END = TOK_KW_YIELD,
TOKEN_TYPE__END = TOKEN_TYPE__KEYWORD_END
} jsp_token_type_t;
/* Flags, describing token properties */
typedef enum
{
JSP_TOKEN_FLAG__NO_FLAGS = 0x00, /* default flag */
JSP_TOKEN_FLAG_PRECEDED_BY_NEWLINES = 0x01 /* designates that newline precedes the token */
} jsp_token_flag_t;
typedef lit_utf8_iterator_pos_t locus;
/* Represents the contents of a token. */
typedef struct
{
locus loc; /**< token location */
uint16_t uid; /**< encodes token's value, depending on token type */
uint8_t type; /**< token type */
uint8_t flags; /**< token flags */
} token;
/**
* Initializer for empty token
*/
#define TOKEN_EMPTY_INITIALIZER {LIT_ITERATOR_POS_ZERO, 0, TOK_EMPTY, JSP_TOKEN_FLAG__NO_FLAGS}
void lexer_init (const jerry_api_char_t *, size_t, bool);
token lexer_next_token (bool, bool);
void lexer_seek (locus);
void lexer_locus_to_line_and_column (locus, size_t *, size_t *);
void lexer_dump_line (size_t);
const char *lexer_token_type_to_string (jsp_token_type_t);
jsp_token_type_t lexer_get_token_type (token);
bool lexer_is_preceded_by_newlines (token);
extern bool lexer_are_tokens_with_same_identifier (token, token);
extern bool lexer_is_no_escape_sequences_in_token_string (token);
#endif
File diff suppressed because it is too large Load Diff
-199
View File
@@ -1,199 +0,0 @@
/* Copyright 2014-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 OPCODES_DUMPER_H
#define OPCODES_DUMPER_H
#include "ecma-globals.h"
#include "jsp-internal.h"
#include "lexer.h"
#include "lit-literal.h"
#include "opcodes.h"
#include "rcs-records.h"
#include "scopes-tree.h"
/**
* Operand types
*/
typedef enum __attr_packed___
{
JSP_OPERAND_TYPE_EMPTY, /**< empty operand */
JSP_OPERAND_TYPE_STRING_LITERAL, /**< operand contains string literal value */
JSP_OPERAND_TYPE_NUMBER_LITERAL, /**< operand contains number literal value */
JSP_OPERAND_TYPE_REGEXP_LITERAL, /**< operand contains regexp literal value */
JSP_OPERAND_TYPE_SIMPLE_VALUE, /**< operand contains a simple ecma value */
JSP_OPERAND_TYPE_SMALLINT, /**< operand contains small integer value (less than 256) */
JSP_OPERAND_TYPE_IDENTIFIER, /**< Identifier reference */
JSP_OPERAND_TYPE_THIS_BINDING, /**< ThisBinding operand */
JSP_OPERAND_TYPE_TMP, /**< operand contains byte-code register index */
JSP_OPERAND_TYPE_IDX_CONST, /**< operand contains an integer constant that fits vm_idx_t */
JSP_OPERAND_TYPE_UNKNOWN, /**< operand, representing unknown value that would be rewritten later */
JSP_OPERAND_TYPE_UNINITIALIZED /**< uninitialized operand
*
* Note:
* For use only in assertions to check that operands
* are initialized before actual usage */
} jsp_operand_type_t;
/**
* Operand (descriptor of value or reference in context of parser)
*/
typedef struct
{
union
{
vm_idx_t idx_const; /**< idx constant value (for jsp_operand_t::IDX_CONST) */
vm_idx_t uid; /**< register index (for jsp_operand_t::TMP) */
lit_cpointer_t lit_id; /**< literal (for jsp_operand_t::LITERAL) */
lit_cpointer_t identifier; /**< Identifier reference (is_value_based_ref flag not set) */
uint8_t smallint_value; /**< small integer value */
uint8_t simple_value; /**< simple ecma value */
} data;
jsp_operand_type_t type; /**< type of operand */
} jsp_operand_t;
extern jsp_operand_t jsp_make_uninitialized_operand (void);
extern jsp_operand_t jsp_make_empty_operand (void);
extern jsp_operand_t jsp_make_this_operand (void);
extern jsp_operand_t jsp_make_unknown_operand (void);
extern jsp_operand_t jsp_make_idx_const_operand (vm_idx_t);
extern jsp_operand_t jsp_make_smallint_operand (uint8_t);
extern jsp_operand_t jsp_make_simple_value_operand (ecma_simple_value_t);
extern jsp_operand_t jsp_make_string_lit_operand (lit_cpointer_t);
extern jsp_operand_t jsp_make_regexp_lit_operand (lit_cpointer_t);
extern jsp_operand_t jsp_make_number_lit_operand (lit_cpointer_t);
extern jsp_operand_t jsp_make_identifier_operand (lit_cpointer_t);
extern jsp_operand_t jsp_make_reg_operand (vm_idx_t);
extern bool jsp_is_empty_operand (jsp_operand_t);
extern bool jsp_is_this_operand (jsp_operand_t);
extern bool jsp_is_unknown_operand (jsp_operand_t);
extern bool jsp_is_idx_const_operand (jsp_operand_t);
extern bool jsp_is_register_operand (jsp_operand_t);
extern bool jsp_is_simple_value_operand (jsp_operand_t);
extern bool jsp_is_smallint_operand (jsp_operand_t);
extern bool jsp_is_number_lit_operand (jsp_operand_t);
extern bool jsp_is_string_lit_operand (jsp_operand_t);
extern bool jsp_is_regexp_lit_operand (jsp_operand_t);
extern bool jsp_is_identifier_operand (jsp_operand_t);
extern lit_cpointer_t jsp_operand_get_identifier_name (jsp_operand_t);
extern lit_cpointer_t jsp_operand_get_literal (jsp_operand_t);
extern vm_idx_t jsp_operand_get_idx (jsp_operand_t);
extern vm_idx_t jsp_operand_get_idx_const (jsp_operand_t);
extern ecma_simple_value_t jsp_operand_get_simple_value (jsp_operand_t);
extern uint8_t jsp_operand_get_smallint_value (jsp_operand_t);
JERRY_STATIC_ASSERT (sizeof (jsp_operand_t) == 4);
typedef enum __attr_packed___
{
VARG_FUNC_DECL,
VARG_FUNC_EXPR,
VARG_ARRAY_DECL,
VARG_OBJ_DECL,
VARG_CONSTRUCT_EXPR,
VARG_CALL_EXPR
} varg_list_type;
extern jsp_operand_t empty_operand (void);
extern jsp_operand_t tmp_operand (void);
extern bool operand_is_empty (jsp_operand_t);
extern void dumper_init (jsp_ctx_t *, bool);
extern vm_instr_counter_t dumper_get_current_instr_counter (jsp_ctx_t *);
extern void dumper_start_move_of_vars_to_regs (jsp_ctx_t *);
extern bool dumper_start_move_of_args_to_regs (jsp_ctx_t *, uint32_t args_num);
extern bool dumper_try_replace_identifier_name_with_reg (jsp_ctx_t *, bytecode_data_header_t *, op_meta *);
extern void dumper_alloc_reg_for_unused_arg (jsp_ctx_t *);
extern void dumper_new_statement (jsp_ctx_t *);
extern void dumper_save_reg_alloc_ctx (jsp_ctx_t *, vm_idx_t *, vm_idx_t *);
extern void dumper_restore_reg_alloc_ctx (jsp_ctx_t *, vm_idx_t, vm_idx_t, bool);
extern vm_idx_t dumper_save_reg_alloc_counter (jsp_ctx_t *);
extern void dumper_restore_reg_alloc_counter (jsp_ctx_t *, vm_idx_t);
extern bool dumper_is_eval_literal (jsp_operand_t);
extern void dump_variable_assignment (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern vm_instr_counter_t dump_varg_header_for_rewrite (jsp_ctx_t *, varg_list_type, jsp_operand_t, jsp_operand_t);
extern void rewrite_varg_header_set_args_count (jsp_ctx_t *, size_t, vm_instr_counter_t);
extern void dump_call_additional_info (jsp_ctx_t *, opcode_call_flags_t, jsp_operand_t);
extern void dump_varg (jsp_ctx_t *, jsp_operand_t);
extern void dump_prop_name_and_value (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_prop_getter_decl (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_prop_setter_decl (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_prop_getter (jsp_ctx_t *, jsp_operand_t, jsp_operand_t, jsp_operand_t);
extern void dump_prop_setter (jsp_ctx_t *, jsp_operand_t, jsp_operand_t, jsp_operand_t);
extern vm_instr_counter_t dump_conditional_check_for_rewrite (jsp_ctx_t *, jsp_operand_t);
extern void rewrite_conditional_check (jsp_ctx_t *, vm_instr_counter_t);
extern vm_instr_counter_t dump_jump_to_end_for_rewrite (jsp_ctx_t *);
extern void rewrite_jump_to_end (jsp_ctx_t *, vm_instr_counter_t);
extern vm_instr_counter_t dumper_set_next_iteration_target (jsp_ctx_t *);
extern vm_instr_counter_t dump_simple_or_nested_jump_for_rewrite (jsp_ctx_t *,
bool,
bool,
bool,
jsp_operand_t,
vm_instr_counter_t);
extern vm_instr_counter_t rewrite_simple_or_nested_jump_and_get_next (jsp_ctx_t *,
vm_instr_counter_t,
vm_instr_counter_t);
extern void dump_continue_iterations_check (jsp_ctx_t *, vm_instr_counter_t, jsp_operand_t);
extern void dump_delete (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_delete_prop (jsp_ctx_t *, jsp_operand_t, jsp_operand_t, jsp_operand_t);
extern void dump_typeof (jsp_ctx_t *, jsp_operand_t, jsp_operand_t);
extern void dump_unary_op (jsp_ctx_t *, vm_op_t, jsp_operand_t, jsp_operand_t);
extern void dump_binary_op (jsp_ctx_t *, vm_op_t, jsp_operand_t, jsp_operand_t, jsp_operand_t);
extern vm_instr_counter_t dump_with_for_rewrite (jsp_ctx_t *, jsp_operand_t);
extern void rewrite_with (jsp_ctx_t *, vm_instr_counter_t);
extern void dump_with_end (jsp_ctx_t *);
extern vm_instr_counter_t dump_for_in_for_rewrite (jsp_ctx_t *, jsp_operand_t);
extern void rewrite_for_in (jsp_ctx_t *, vm_instr_counter_t);
extern void dump_for_in_end (jsp_ctx_t *);
extern vm_instr_counter_t dump_try_for_rewrite (jsp_ctx_t *);
extern vm_instr_counter_t dump_catch_for_rewrite (jsp_ctx_t *, jsp_operand_t);
extern vm_instr_counter_t dump_finally_for_rewrite (jsp_ctx_t *);
extern void rewrite_try (jsp_ctx_t *, vm_instr_counter_t);
extern void rewrite_catch (jsp_ctx_t *, vm_instr_counter_t);
extern void rewrite_finally (jsp_ctx_t *, vm_instr_counter_t);
extern void dump_end_try_catch_finally (jsp_ctx_t *);
extern void dump_throw (jsp_ctx_t *, jsp_operand_t);
extern void dump_variable_declaration (jsp_ctx_t *, lit_cpointer_t);
extern vm_instr_counter_t dump_reg_var_decl_for_rewrite (jsp_ctx_t *);
extern void rewrite_reg_var_decl (jsp_ctx_t *, vm_instr_counter_t);
extern void dump_ret (jsp_ctx_t *);
extern void dump_retval (jsp_ctx_t *, jsp_operand_t);
extern op_meta dumper_get_op_meta (jsp_ctx_t *, vm_instr_counter_t);
extern void dumper_rewrite_op_meta (jsp_ctx_t *, vm_instr_counter_t, op_meta);
#endif /* !OPCODES_DUMPER_H */
File diff suppressed because it is too large Load Diff
+28 -8
View File
@@ -1,4 +1,4 @@
/* Copyright 2014-2015 Samsung Electronics Co., Ltd.
/* Copyright 2014-2016 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.
@@ -16,20 +16,40 @@
#ifndef PARSER_H
#define PARSER_H
#include "jrt.h"
#include "jerry-api.h"
#include "byte-code.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup jsparser ECMAScript
* @{
*
* \addtogroup jsparser_parser Parser
* @{
*/
/**
* Parser completion status
*/
typedef enum
{
JSP_STATUS_OK, /**< parse finished successfully, no early errors occured */
JSP_STATUS_SYNTAX_ERROR, /**< SyntaxError early error occured */
JSP_STATUS_OK, /**< parse finished successfully, no early errors occured */
JSP_STATUS_SYNTAX_ERROR, /**< SyntaxError early error occured */
JSP_STATUS_REFERENCE_ERROR /**< ReferenceError early error occured */
} jsp_status_t;
void parser_set_show_instrs (bool);
jsp_status_t parser_parse_script (const jerry_api_char_t *, size_t, const bytecode_data_header_t **);
jsp_status_t parser_parse_eval (const jerry_api_char_t *, size_t, bool, const bytecode_data_header_t **, bool *);
extern void parser_set_show_instrs (int);
#endif /* PARSER_H */
extern jsp_status_t parser_parse_script (const jerry_api_char_t *, size_t,
ecma_compiled_code_t **);
extern jsp_status_t parser_parse_eval (const jerry_api_char_t *, size_t, bool,
ecma_compiled_code_t **);
/**
* @}
* @}
* @}
*/
#endif /* !PARSER_H */
-296
View File
@@ -1,296 +0,0 @@
/* Copyright 2014-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 "bytecode-data.h"
#include "jsp-mm.h"
#include "scopes-tree.h"
scopes_tree scopes_tree_root_node_p = NULL;
scopes_tree scopes_tree_last_node_p = NULL;
static void
assert_tree (scopes_tree t)
{
JERRY_ASSERT (t != NULL);
}
vm_instr_counter_t
scopes_tree_instrs_num (scopes_tree t)
{
assert_tree (t);
return t->instrs_count;
}
/**
* Get number of variable declarations in the scope
*
* @return number of variable declarations
*/
vm_instr_counter_t
scopes_tree_var_decls_num (scopes_tree t) /**< scope */
{
assert_tree (t);
return linked_list_get_length (t->var_decls);
} /* scopes_tree_var_decls_num */
/**
* Add variable declaration to a scope
*/
void
scopes_tree_add_var_decl (scopes_tree tree, /**< scope, to which variable declaration is added */
op_meta op) /**< variable declaration instruction */
{
assert_tree (tree);
linked_list_set_element (tree->var_decls, linked_list_get_length (tree->var_decls), &op);
} /* scopes_tree_add_var_decl */
/**
* Get variable declaration for the specified scope
*
* @return instruction, declaring a variable
*/
op_meta
scopes_tree_var_decl (scopes_tree tree, /**< scope, from which variable declaration is retrieved */
vm_instr_counter_t oc) /**< number of variable declaration in the scope */
{
assert_tree (tree);
JERRY_ASSERT (oc < linked_list_get_length (tree->var_decls));
return *(op_meta *) linked_list_element (tree->var_decls, oc);
} /* scopes_tree_var_decl */
/**
* Checks if variable declaration exists in the scope
*
* @return true / false
*/
bool
scopes_tree_variable_declaration_exists (scopes_tree tree, /**< scope */
lit_cpointer_t lit_id) /**< literal which holds variable's name */
{
assert_tree (tree);
for (vm_instr_counter_t oc = 0u;
oc < linked_list_get_length (tree->var_decls);
oc++)
{
const op_meta* var_decl_om_p = (op_meta *) linked_list_element (tree->var_decls, oc);
JERRY_ASSERT (var_decl_om_p->op.op_idx == VM_OP_VAR_DECL);
JERRY_ASSERT (var_decl_om_p->op.data.var_decl.variable_name == VM_IDX_REWRITE_LITERAL_UID);
if (var_decl_om_p->lit_id[0].packed_value == lit_id.packed_value)
{
return true;
}
}
return false;
} /* scopes_tree_variable_declaration_exists */
/**
* Fill variable declaration list of bytecode header
*/
void
scopes_tree_dump_var_decls (scopes_tree scope, /**< scopes tree */
lit_cpointer_t *var_decls_p) /**< pointer to bytecode header's declarations table,
* where variables' lit_cp's should be stored */
{
for (uint32_t i = 0; i < scopes_tree_var_decls_num (scope); ++i)
{
op_meta var_decl_op_meta = *(op_meta *) linked_list_element (scope->var_decls, i);
var_decls_p[i] = var_decl_op_meta.lit_id[0];
}
} /* scopes_tree_dump_var_decls */
/**
* Set up a flag, indicating that scope should be executed in strict mode
*/
void
scopes_tree_set_strict_mode (scopes_tree tree, /**< scope */
bool strict_mode) /**< value of the strict mode flag */
{
assert_tree (tree);
tree->strict_mode = strict_mode;
} /* scopes_tree_set_strict_mode */
/**
* Set up a flag, indicating that "arguments" is used inside a scope
*/
void
scopes_tree_set_arguments_used (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->ref_arguments = true;
} /* merge_subscopes */
/**
* Set up a flag, indicating that "eval" is used inside a scope
*/
void
scopes_tree_set_eval_used (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->ref_eval = true;
} /* scopes_tree_set_eval_used */
/**
* Set up a flag, indicating that 'with' statement is contained in a scope
*/
void
scopes_tree_set_contains_with (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->contains_with = true;
} /* scopes_tree_set_contains_with */
/**
* Set up a flag, indicating that 'try' statement is contained in a scope
*/
void
scopes_tree_set_contains_try (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->contains_try = true;
} /* scopes_tree_set_contains_try */
/**
* Set up a flag, indicating that 'delete' operator is contained in a scope
*/
void
scopes_tree_set_contains_delete (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->contains_delete = true;
} /* scopes_tree_set_contains_delete */
/**
* Set up a flag, indicating that there is a function declaration / expression inside a scope
*/
void
scopes_tree_set_contains_functions (scopes_tree tree) /**< scope */
{
assert_tree (tree);
tree->contains_functions = true;
} /* scopes_tree_set_contains_functions */
bool
scopes_tree_strict_mode (scopes_tree tree)
{
assert_tree (tree);
return (bool) tree->strict_mode;
}
/**
* Get number of subscopes (immediate function declarations / expressions) of the specified scope
*
* @return the number
*/
size_t
scopes_tree_child_scopes_num (scopes_tree tree) /**< a scopes tree node */
{
return tree->child_scopes_num;
} /* scopes_tree_child_scopes_num */
void
scopes_tree_init (void)
{
scopes_tree_root_node_p = NULL;
scopes_tree_last_node_p = NULL;
} /* scopes_tree_init */
void
scopes_tree_finalize (void)
{
JERRY_ASSERT (scopes_tree_root_node_p == NULL);
JERRY_ASSERT (scopes_tree_last_node_p == NULL);
} /* scopes_tree_finalize */
/**
* Initialize a scope
*
* @return initialized scope
*/
scopes_tree
scopes_tree_new_scope (scopes_tree parent, /**< parent scope */
scope_type_t type) /**< scope type */
{
scopes_tree tree = (scopes_tree) jsp_mm_alloc (sizeof (scopes_tree_int));
tree->child_scopes_num = 0;
tree->child_scopes_processed_num = 0;
tree->max_uniq_literals_num = 0;
tree->bc_header_cp = MEM_CP_NULL;
tree->next_scope_cp = MEM_CP_NULL;
tree->instrs_count = 0;
tree->type = type;
tree->strict_mode = false;
tree->ref_arguments = false;
tree->ref_eval = false;
tree->contains_with = false;
tree->contains_try = false;
tree->contains_delete = false;
tree->contains_functions = false;
tree->is_vars_and_args_to_regs_possible = false;
tree->var_decls = linked_list_init (sizeof (op_meta));
if (parent != NULL)
{
JERRY_ASSERT (scopes_tree_root_node_p != NULL);
JERRY_ASSERT (scopes_tree_last_node_p != NULL);
parent->child_scopes_num++;
}
else
{
JERRY_ASSERT (scopes_tree_root_node_p == NULL);
JERRY_ASSERT (scopes_tree_last_node_p == NULL);
scopes_tree_root_node_p = tree;
scopes_tree_last_node_p = tree;
}
MEM_CP_SET_NON_NULL_POINTER (scopes_tree_last_node_p->next_scope_cp, tree);
tree->next_scope_cp = MEM_CP_NULL;
scopes_tree_last_node_p = tree;
return tree;
} /* scopes_tree_new_scope */
void
scopes_tree_finish_build (void)
{
JERRY_ASSERT (scopes_tree_root_node_p != NULL);
JERRY_ASSERT (scopes_tree_last_node_p != NULL);
scopes_tree_root_node_p = NULL;
scopes_tree_last_node_p = NULL;
} /* scopes_tree_finish_build */
void
scopes_tree_free_scope (scopes_tree scope_p)
{
assert_tree (scope_p);
JERRY_ASSERT (scopes_tree_root_node_p == NULL);
JERRY_ASSERT (scopes_tree_last_node_p == NULL);
linked_list_free (scope_p->var_decls);
jsp_mm_free (scope_p);
} /* scopes_tree_free_scope */
-112
View File
@@ -1,112 +0,0 @@
/* Copyright 2014-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 SCOPES_TREE_H
#define SCOPES_TREE_H
#include "linked-list.h"
#include "lexer.h"
#include "ecma-globals.h"
#include "opcodes.h"
#include "lit-id-hash-table.h"
#include "lit-literal.h"
/**
* Intermediate instruction descriptor that additionally to byte-code instruction
* holds information about literals, associated with corresponding arguments
* of the instruction.
*/
typedef struct
{
lit_cpointer_t lit_id[3]; /**< literals, corresponding to arguments
* (NOT_A_LITERAL - if not literal is associated
* with corresponding argument) */
vm_instr_t op; /**< byte-code instruction */
} op_meta;
typedef struct tree_header
{
linked_list children;
} tree_header;
/**
* Scope type
*/
typedef enum __attr_packed___
{
SCOPE_TYPE_GLOBAL, /**< the Global code scope */
SCOPE_TYPE_FUNCTION, /**< a function code scope */
SCOPE_TYPE_EVAL /**< an eval code scope */
} scope_type_t;
/**
* Structure for holding scope information during parsing
*/
typedef struct
{
mem_cpointer_t next_scope_cp; /**< next scope with same parent */
mem_cpointer_t bc_header_cp; /**< pointer to corresponding byte-code header
* (after bc_dump_single_scope) */
uint16_t child_scopes_num; /**< number of child scopes */
uint16_t child_scopes_processed_num; /**< number of child scopes, for which
* byte-code headers were already constructed */
uint16_t max_uniq_literals_num; /**< upper estimate number of entries
* in idx-literal hash table */
vm_instr_counter_t instrs_count; /**< count of instructions */
linked_list var_decls; /**< instructions for variable declarations */
scope_type_t type : 2; /**< scope type */
bool strict_mode: 1; /**< flag, indicating that scope's code should be executed in strict mode */
bool ref_arguments: 1; /**< flag, indicating that "arguments" variable is used inside the scope
* (not depends on subscopes) */
bool ref_eval: 1; /**< flag, indicating that "eval" is used inside the scope
* (not depends on subscopes) */
bool contains_with: 1; /**< flag, indicationg whether 'with' statement is contained in the scope
* (not depends on subscopes) */
bool contains_try: 1; /**< flag, indicationg whether 'try' statement is contained in the scope
* (not depends on subscopes) */
bool contains_delete: 1; /**< flag, indicationg whether 'delete' operator is contained in the scope
* (not depends on subscopes) */
bool contains_functions: 1; /**< flag, indicating that the scope contains a function declaration / expression */
bool is_vars_and_args_to_regs_possible : 1; /**< the function's variables / arguments can be moved to registers */
} scopes_tree_int;
typedef scopes_tree_int *scopes_tree;
void scopes_tree_init (void);
void scopes_tree_finalize (void);
scopes_tree scopes_tree_new_scope (scopes_tree, scope_type_t);
void scopes_tree_free_scope (scopes_tree);
void scopes_tree_finish_build (void);
size_t scopes_tree_child_scopes_num (scopes_tree);
vm_instr_counter_t scopes_tree_instrs_num (scopes_tree);
vm_instr_counter_t scopes_tree_var_decls_num (scopes_tree);
void scopes_tree_add_var_decl (scopes_tree, op_meta);
op_meta scopes_tree_var_decl (scopes_tree, vm_instr_counter_t);
bool scopes_tree_variable_declaration_exists (scopes_tree, lit_cpointer_t);
void scopes_tree_dump_var_decls (scopes_tree, lit_cpointer_t *);
void scopes_tree_set_strict_mode (scopes_tree, bool);
void scopes_tree_set_arguments_used (scopes_tree);
void scopes_tree_set_eval_used (scopes_tree);
void scopes_tree_set_contains_with (scopes_tree);
void scopes_tree_set_contains_try (scopes_tree);
void scopes_tree_set_contains_delete (scopes_tree);
void scopes_tree_set_contains_functions (scopes_tree);
bool scopes_tree_strict_mode (scopes_tree);
#endif /* SCOPES_TREE_H */
+67 -34
View File
@@ -1,5 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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.
@@ -25,6 +25,16 @@
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
/** \addtogroup parser Parser
* @{
*
* \addtogroup regexparser Regular expression
* @{
*
* \addtogroup regexparser_bytecode Bytecode
* @{
*/
/**
* Size of block of RegExp bytecode. Used for allocation
*/
@@ -34,7 +44,7 @@
* Get length of bytecode
*/
static uint32_t
re_get_bytecode_length (re_bytecode_ctx_t *bc_ctx_p)
re_get_bytecode_length (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */
{
return ((uint32_t) (bc_ctx_p->current_p - bc_ctx_p->block_start_p));
} /* re_get_bytecode_length */
@@ -47,7 +57,7 @@ re_dump_bytecode (re_bytecode_ctx_t *bc_ctx);
*
* @return current position in RegExp bytecode
*/
static re_bytecode_t*
static uint8_t *
re_realloc_regexp_bytecode_block (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */
{
JERRY_ASSERT (bc_ctx_p->block_end_p - bc_ctx_p->block_start_p >= 0);
@@ -62,8 +72,8 @@ re_realloc_regexp_bytecode_block (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytec
JERRY_ASSERT (bc_ctx_p->current_p - bc_ctx_p->block_start_p >= 0);
size_t current_ptr_offset = static_cast<size_t> (bc_ctx_p->current_p - bc_ctx_p->block_start_p);
re_bytecode_t *new_block_start_p = (re_bytecode_t *) mem_heap_alloc_block (new_block_size,
MEM_HEAP_ALLOC_SHORT_TERM);
uint8_t *new_block_start_p = (uint8_t *) mem_heap_alloc_block (new_block_size,
MEM_HEAP_ALLOC_SHORT_TERM);
if (bc_ctx_p->current_p)
{
memcpy (new_block_start_p, bc_ctx_p->block_start_p, static_cast<size_t> (current_ptr_offset));
@@ -81,12 +91,12 @@ re_realloc_regexp_bytecode_block (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytec
*/
static void
re_bytecode_list_append (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
re_bytecode_t *bytecode_p, /**< input bytecode */
uint8_t *bytecode_p, /**< input bytecode */
size_t length) /**< length of input */
{
JERRY_ASSERT (length <= REGEXP_BYTECODE_BLOCK_SIZE);
re_bytecode_t *current_p = bc_ctx_p->current_p;
uint8_t *current_p = bc_ctx_p->current_p;
if (current_p + length > bc_ctx_p->block_end_p)
{
current_p = re_realloc_regexp_bytecode_block (bc_ctx_p);
@@ -102,24 +112,24 @@ re_bytecode_list_append (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode conte
static void
re_bytecode_list_insert (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
size_t offset, /**< distance from the start of the container */
re_bytecode_t *bytecode_p, /**< input bytecode */
uint8_t *bytecode_p, /**< input bytecode */
size_t length) /**< length of input */
{
JERRY_ASSERT (length <= REGEXP_BYTECODE_BLOCK_SIZE);
re_bytecode_t *current_p = bc_ctx_p->current_p;
uint8_t *current_p = bc_ctx_p->current_p;
if (current_p + length > bc_ctx_p->block_end_p)
{
re_realloc_regexp_bytecode_block (bc_ctx_p);
}
re_bytecode_t *src_p = bc_ctx_p->block_start_p + offset;
uint8_t *src_p = bc_ctx_p->block_start_p + offset;
if ((re_get_bytecode_length (bc_ctx_p) - offset) > 0)
{
re_bytecode_t *dest_p = src_p + length;
re_bytecode_t *tmp_block_start_p;
tmp_block_start_p = (re_bytecode_t *) mem_heap_alloc_block ((re_get_bytecode_length (bc_ctx_p) - offset),
MEM_HEAP_ALLOC_SHORT_TERM);
uint8_t *dest_p = src_p + length;
uint8_t *tmp_block_start_p;
tmp_block_start_p = (uint8_t *) mem_heap_alloc_block ((re_get_bytecode_length (bc_ctx_p) - offset),
MEM_HEAP_ALLOC_SHORT_TERM);
memcpy (tmp_block_start_p, src_p, (size_t) (re_get_bytecode_length (bc_ctx_p) - offset));
memcpy (dest_p, tmp_block_start_p, (size_t) (re_get_bytecode_length (bc_ctx_p) - offset));
mem_heap_free_block (tmp_block_start_p);
@@ -136,7 +146,7 @@ static void
re_append_opcode (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
re_opcode_t opcode) /**< input opcode */
{
re_bytecode_list_append (bc_ctx_p, (re_bytecode_t*) &opcode, sizeof (re_bytecode_t));
re_bytecode_list_append (bc_ctx_p, (uint8_t*) &opcode, sizeof (uint8_t));
} /* re_append_opcode */
/**
@@ -146,7 +156,7 @@ static void
re_append_u32 (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
uint32_t value) /**< input value */
{
re_bytecode_list_append (bc_ctx_p, (re_bytecode_t*) &value, sizeof (uint32_t));
re_bytecode_list_append (bc_ctx_p, (uint8_t*) &value, sizeof (uint32_t));
} /* re_append_u32 */
/**
@@ -168,7 +178,7 @@ re_insert_opcode (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
uint32_t offset, /**< distance from the start of the container */
re_opcode_t opcode) /**< input opcode */
{
re_bytecode_list_insert (bc_ctx_p, offset, (re_bytecode_t*) &opcode, sizeof (re_bytecode_t));
re_bytecode_list_insert (bc_ctx_p, offset, (uint8_t*) &opcode, sizeof (uint8_t));
} /* re_insert_opcode */
/**
@@ -179,17 +189,17 @@ re_insert_u32 (re_bytecode_ctx_t *bc_ctx_p, /**< RegExp bytecode context */
uint32_t offset, /**< distance from the start of the container */
uint32_t value) /**< input value */
{
re_bytecode_list_insert (bc_ctx_p, offset, (re_bytecode_t*) &value, sizeof (uint32_t));
re_bytecode_list_insert (bc_ctx_p, offset, (uint8_t*) &value, sizeof (uint32_t));
} /* re_insert_u32 */
/**
* Get a RegExp opcode
*/
re_opcode_t
re_get_opcode (re_bytecode_t **bc_p) /**< pointer to bytecode start */
re_get_opcode (uint8_t **bc_p) /**< pointer to bytecode start */
{
re_bytecode_t bytecode = **bc_p;
(*bc_p) += sizeof (re_bytecode_t);
uint8_t bytecode = **bc_p;
(*bc_p) += sizeof (uint8_t);
return (re_opcode_t) bytecode;
} /* get_opcode */
@@ -197,7 +207,7 @@ re_get_opcode (re_bytecode_t **bc_p) /**< pointer to bytecode start */
* Get a parameter of a RegExp opcode
*/
uint32_t
re_get_value (re_bytecode_t **bc_p) /**< pointer to bytecode start */
re_get_value (uint8_t **bc_p) /**< pointer to bytecode start */
{
uint32_t value = *((uint32_t*) *bc_p);
(*bc_p) += sizeof (uint32_t);
@@ -368,6 +378,13 @@ re_insert_into_group_with_jump (re_compiler_ctx_t *re_ctx_p, /**< RegExp compile
re_insert_into_group (re_ctx_p, group_start_offset, idx, is_capturable);
} /* re_insert_into_group_with_jump */
/**
* @}
*
* \addtogroup regexparser_compiler Compiler
* @{
*/
/**
* Parse alternatives
*
@@ -614,9 +631,9 @@ re_parse_alternative (re_compiler_ctx_t *re_ctx_p, /**< RegExp compiler context
* Returned value must be freed with ecma_free_completion_value
*/
ecma_completion_value_t
re_compile_bytecode (re_bytecode_t **out_bytecode_p, /**< out:pointer to bytecode */
re_compile_bytecode (re_compiled_code_t **out_bytecode_p, /**< out:pointer to bytecode */
ecma_string_t *pattern_str_p, /**< pattern */
uint8_t flags) /**< flags */
uint16_t flags) /**< flags */
{
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
re_compiler_ctx_t re_ctx;
@@ -661,9 +678,18 @@ re_compile_bytecode (re_bytecode_t **out_bytecode_p, /**< out:pointer to bytecod
re_append_opcode (&bc_ctx, RE_OP_EOF);
/* 3. Insert extra informations for bytecode header */
re_insert_u32 (&bc_ctx, 0, (uint32_t) re_ctx.num_of_non_captures);
re_insert_u32 (&bc_ctx, 0, (uint32_t) re_ctx.num_of_captures * 2);
re_insert_u32 (&bc_ctx, 0, (uint32_t) re_ctx.flags);
re_compiled_code_t re_compiled_code;
re_compiled_code.flags = re_ctx.flags | (1 << ECMA_BYTECODE_REF_SHIFT);
ECMA_SET_NON_NULL_POINTER (re_compiled_code.pattern_cp,
ecma_copy_or_ref_ecma_string (pattern_str_p));
re_compiled_code.num_of_captures = re_ctx.num_of_captures * 2;
re_compiled_code.num_of_non_captures = re_ctx.num_of_non_captures;
re_bytecode_list_insert (&bc_ctx,
0,
(uint8_t *) &re_compiled_code,
sizeof (re_compiled_code_t));
}
ECMA_FINALIZE (empty);
@@ -679,7 +705,7 @@ re_compile_bytecode (re_bytecode_t **out_bytecode_p, /**< out:pointer to bytecod
{
/* The RegExp bytecode contains at least a RE_OP_SAVE_AT_START opdoce, so it cannot be NULL. */
JERRY_ASSERT (bc_ctx.block_start_p != NULL);
*out_bytecode_p = bc_ctx.block_start_p;
*out_bytecode_p = (re_compiled_code_t *) bc_ctx.block_start_p;
}
#ifdef JERRY_ENABLE_LOG
@@ -694,12 +720,14 @@ re_compile_bytecode (re_bytecode_t **out_bytecode_p, /**< out:pointer to bytecod
* RegExp bytecode dumper
*/
void
re_dump_bytecode (re_bytecode_ctx_t *bc_ctx_p)
re_dump_bytecode (re_bytecode_ctx_t *bc_ctx_p) /**< RegExp bytecode context */
{
re_bytecode_t *bytecode_p = bc_ctx_p->block_start_p;
JERRY_DLOG ("%d ", re_get_value (&bytecode_p));
JERRY_DLOG ("%d ", re_get_value (&bytecode_p));
JERRY_DLOG ("%d | ", re_get_value (&bytecode_p));
re_compiled_code_t *compiled_code_p = bc_ctx_p->block_start_p;
JERRY_DLOG ("%d ", compiled_code_p->flags);
JERRY_DLOG ("%d ", compiled_code_p->num_of_captures);
JERRY_DLOG ("%d | ", compiled_code_p->num_of_non_captures);
uint8_t *bytecode_p = (uint8_t *) (compiled_code_p + 1);
re_opcode_t op;
while ((op = re_get_opcode (&bytecode_p)))
@@ -891,4 +919,9 @@ re_dump_bytecode (re_bytecode_ctx_t *bc_ctx_p)
} /* re_dump_bytecode */
#endif /* JERRY_ENABLE_LOG */
/**
* @}
* @}
*/
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
+70 -48
View File
@@ -1,5 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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.
@@ -22,6 +22,16 @@
#include "ecma-globals.h"
#include "re-parser.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup regexparser Regular expression
* @{
*
* \addtogroup regexparser_compiler Compiler
* @{
*/
/**
* RegExp opcodes
*/
@@ -31,54 +41,60 @@ typedef enum
/* Group opcode order is important, because RE_IS_CAPTURE_GROUP is based on it.
* Change it carefully. Capture opcodes should be at first.
*/
RE_OP_CAPTURE_GROUP_START,
RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START,
RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START,
RE_OP_CAPTURE_GREEDY_GROUP_END,
RE_OP_CAPTURE_NON_GREEDY_GROUP_END,
RE_OP_NON_CAPTURE_GROUP_START,
RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START,
RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START,
RE_OP_NON_CAPTURE_GREEDY_GROUP_END,
RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END,
RE_OP_CAPTURE_GROUP_START, /**< group start */
RE_OP_CAPTURE_GREEDY_ZERO_GROUP_START, /**< greedy zero group start */
RE_OP_CAPTURE_NON_GREEDY_ZERO_GROUP_START, /**< non-greedy zero group start */
RE_OP_CAPTURE_GREEDY_GROUP_END, /**< greedy group end */
RE_OP_CAPTURE_NON_GREEDY_GROUP_END, /**< non-greedy group end */
RE_OP_NON_CAPTURE_GROUP_START, /**< non-capture group start */
RE_OP_NON_CAPTURE_GREEDY_ZERO_GROUP_START, /**< non-capture greedy zero group start */
RE_OP_NON_CAPTURE_NON_GREEDY_ZERO_GROUP_START, /**< non-capture non-greedy zero group start */
RE_OP_NON_CAPTURE_GREEDY_GROUP_END, /**< non-capture greedy group end */
RE_OP_NON_CAPTURE_NON_GREEDY_GROUP_END, /**< non-capture non-greedy group end */
RE_OP_MATCH,
RE_OP_CHAR,
RE_OP_SAVE_AT_START,
RE_OP_SAVE_AND_MATCH,
RE_OP_PERIOD,
RE_OP_ALTERNATIVE,
RE_OP_GREEDY_ITERATOR,
RE_OP_NON_GREEDY_ITERATOR,
RE_OP_ASSERT_START,
RE_OP_ASSERT_END,
RE_OP_ASSERT_WORD_BOUNDARY,
RE_OP_ASSERT_NOT_WORD_BOUNDARY,
RE_OP_LOOKAHEAD_POS,
RE_OP_LOOKAHEAD_NEG,
RE_OP_BACKREFERENCE,
RE_OP_CHAR_CLASS,
RE_OP_INV_CHAR_CLASS
RE_OP_MATCH, /**< match */
RE_OP_CHAR, /**< any character */
RE_OP_SAVE_AT_START, /**< save at start */
RE_OP_SAVE_AND_MATCH, /**< save and match */
RE_OP_PERIOD, /**< . */
RE_OP_ALTERNATIVE, /**< | */
RE_OP_GREEDY_ITERATOR, /**< greedy iterator */
RE_OP_NON_GREEDY_ITERATOR, /**< non-greedy iterator */
RE_OP_ASSERT_START, /**< ^ */
RE_OP_ASSERT_END, /**< $ */
RE_OP_ASSERT_WORD_BOUNDARY, /**< \b */
RE_OP_ASSERT_NOT_WORD_BOUNDARY, /**< \B */
RE_OP_LOOKAHEAD_POS, /**< lookahead pos */
RE_OP_LOOKAHEAD_NEG, /**< lookahead neg */
RE_OP_BACKREFERENCE, /**< \[0..9] */
RE_OP_CHAR_CLASS, /**< [ ] */
RE_OP_INV_CHAR_CLASS /**< [^ ] */
} re_opcode_t;
/**
* Compiled byte code data.
*/
typedef struct
{
uint16_t flags; /**< RegExp flags */
mem_cpointer_t pattern_cp; /**< original RegExp pattern */
uint32_t num_of_captures; /**< number of capturing brackets */
uint32_t num_of_non_captures; /**< number of non capturing brackets */
} re_compiled_code_t;
/**
* Check if a RegExp opcode is a capture group or not
*/
#define RE_IS_CAPTURE_GROUP(x) (((x) < RE_OP_NON_CAPTURE_GROUP_START) ? 1 : 0)
/**
* Type of bytecode elements
*/
typedef uint8_t re_bytecode_t;
/**
* Context of RegExp bytecode container
*/
typedef struct
{
re_bytecode_t *block_start_p; /**< start of bytecode block */
re_bytecode_t *block_end_p; /**< end of bytecode block */
re_bytecode_t *current_p; /**< current position in bytecode */
uint8_t *block_start_p; /**< start of bytecode block */
uint8_t *block_end_p; /**< end of bytecode block */
uint8_t *current_p; /**< current position in bytecode */
} re_bytecode_ctx_t;
/**
@@ -86,23 +102,29 @@ typedef struct
*/
typedef struct
{
uint8_t flags; /**< RegExp flags */
uint32_t num_of_captures; /**< number of capture groups */
uint32_t num_of_non_captures; /**< number of non-capture groups */
uint32_t highest_backref; /**< highest backreference */
uint16_t flags; /**< RegExp flags */
uint32_t num_of_captures; /**< number of capture groups */
uint32_t num_of_non_captures; /**< number of non-capture groups */
uint32_t highest_backref; /**< highest backreference */
re_bytecode_ctx_t *bytecode_ctx_p; /**< pointer of RegExp bytecode context */
re_token_t current_token; /**< current token */
re_parser_ctx_t *parser_ctx_p; /**< pointer of RegExp parser context */
re_token_t current_token; /**< current token */
re_parser_ctx_t *parser_ctx_p; /**< pointer of RegExp parser context */
} re_compiler_ctx_t;
ecma_completion_value_t
re_compile_bytecode (re_bytecode_t **, ecma_string_t *, uint8_t);
re_compile_bytecode (re_compiled_code_t **, ecma_string_t *, uint16_t);
re_opcode_t
re_get_opcode (re_bytecode_t **);
re_get_opcode (uint8_t **);
uint32_t
re_get_value (re_bytecode_t **);
re_get_value (uint8_t **);
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
#endif /* RE_COMPILER_H */
/**
* @}
* @}
* @}
*/
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
#endif /* !RE_COMPILER_H */
+17 -1
View File
@@ -24,6 +24,16 @@
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
/** \addtogroup parser Parser
* @{
*
* \addtogroup regexparser Regular expression
* @{
*
* \addtogroup regexparser_parser Parser
* @{
*/
/**
* Lookup a character in the input string.
*
@@ -894,4 +904,10 @@ re_parse_next_token (re_parser_ctx_t *parser_ctx_p, /**< RegExp parser context *
return ret_value;
} /* re_parse_next_token */
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
/**
* @}
* @}
* @}
*/
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
+61 -40
View File
@@ -1,5 +1,5 @@
/* Copyright 2015 Samsung Electronics Co., Ltd.
* Copyright 2015 University of Szeged.
/* Copyright 2015-2016 Samsung Electronics Co., Ltd.
* Copyright 2015-2016 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.
@@ -19,49 +19,65 @@
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN
#include "opcodes-dumper.h"
/** \addtogroup parser Parser
* @{
*
* \addtogroup regexparser Regular expression
* @{
*
* \addtogroup regexparser_bytecode Bytecode
* @{
*/
/**
* RegExp token type definitions
*/
typedef enum
{
RE_TOK_EOF, /* EOF */
RE_TOK_BACKREFERENCE, /* \[0..9] */
RE_TOK_CHAR, /* any character */
RE_TOK_ALTERNATIVE, /* | */
RE_TOK_ASSERT_START, /* ^ */
RE_TOK_ASSERT_END, /* $ */
RE_TOK_PERIOD, /* . */
RE_TOK_START_CAPTURE_GROUP, /* ( */
RE_TOK_START_NON_CAPTURE_GROUP, /* (?: */
RE_TOK_END_GROUP, /* ')' */
RE_TOK_EOF, /* EOF */
RE_TOK_BACKREFERENCE, /* \[0..9] */
RE_TOK_CHAR, /* any character */
RE_TOK_ALTERNATIVE, /* | */
RE_TOK_ASSERT_START, /* ^ */
RE_TOK_ASSERT_END, /* $ */
RE_TOK_PERIOD, /* . */
RE_TOK_START_CAPTURE_GROUP, /* ( */
RE_TOK_START_NON_CAPTURE_GROUP, /* (?: */
RE_TOK_END_GROUP, /* ')' */
RE_TOK_ASSERT_START_POS_LOOKAHEAD, /* (?= */
RE_TOK_ASSERT_START_NEG_LOOKAHEAD, /* (?! */
RE_TOK_ASSERT_WORD_BOUNDARY, /* \b */
RE_TOK_ASSERT_NOT_WORD_BOUNDARY, /* \B */
RE_TOK_DIGIT, /* \d */
RE_TOK_NOT_DIGIT, /* \D */
RE_TOK_WHITE, /* \s */
RE_TOK_NOT_WHITE, /* \S */
RE_TOK_WORD_CHAR, /* \w */
RE_TOK_NOT_WORD_CHAR, /* \W */
RE_TOK_START_CHAR_CLASS, /* [ ] */
RE_TOK_START_INV_CHAR_CLASS, /* [^ ] */
RE_TOK_ASSERT_WORD_BOUNDARY, /* \b */
RE_TOK_ASSERT_NOT_WORD_BOUNDARY, /* \B */
RE_TOK_DIGIT, /* \d */
RE_TOK_NOT_DIGIT, /* \D */
RE_TOK_WHITE, /* \s */
RE_TOK_NOT_WHITE, /* \S */
RE_TOK_WORD_CHAR, /* \w */
RE_TOK_NOT_WORD_CHAR, /* \W */
RE_TOK_START_CHAR_CLASS, /* [ ] */
RE_TOK_START_INV_CHAR_CLASS, /* [^ ] */
} re_token_type_t;
/**
* RegExp constant of infinite
*/
* @}
*
* \addtogroup regexparser_parser Parser
* @{
*/
/**
* RegExp constant of infinite
*/
#define RE_ITERATOR_INFINITE ((uint32_t)-1)
/**
* Maximum number of decimal escape digits
*/
* Maximum number of decimal escape digits
*/
#define RE_MAX_RE_DECESC_DIGITS 9
/**
* Undefined character (out of the range of the codeunit)
*/
* Undefined character (out of the range of the codeunit)
*/
#define RE_CHAR_UNDEF 0xFFFFFFFF
/**
@@ -69,11 +85,11 @@ typedef enum
*/
typedef struct
{
re_token_type_t type; /**< type of the token */
uint32_t value; /**< value of the token */
uint32_t qmin; /**< minimum number of token iterations */
uint32_t qmax; /**< maximum number of token iterations */
bool greedy; /**< type of iteration */
re_token_type_t type; /**< type of the token */
uint32_t value; /**< value of the token */
uint32_t qmin; /**< minimum number of token iterations */
uint32_t qmax; /**< maximum number of token iterations */
bool greedy; /**< type of iteration */
} re_token_t;
/**
@@ -82,10 +98,10 @@ typedef struct
typedef struct
{
lit_utf8_byte_t *input_start_p; /**< start of input pattern */
lit_utf8_byte_t *input_curr_p; /**< current position in input pattern */
lit_utf8_byte_t *input_end_p; /**< end of input pattern */
int num_of_groups; /**< number of groups */
uint32_t num_of_classes; /**< number of character classes */
lit_utf8_byte_t *input_curr_p; /**< current position in input pattern */
lit_utf8_byte_t *input_end_p; /**< end of input pattern */
int num_of_groups; /**< number of groups */
uint32_t num_of_classes; /**< number of character classes */
} re_parser_ctx_t;
typedef void (*re_char_class_callback) (void *re_ctx_p, uint32_t start, uint32_t end);
@@ -96,5 +112,10 @@ re_parse_char_class (re_parser_ctx_t *, re_char_class_callback, void *, re_token
ecma_completion_value_t
re_parse_next_token (re_parser_ctx_t *, re_token_t *);
#endif /* CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
#endif /* RE_PARSER_H */
/**
* @}
* @}
*/
#endif /* !CONFIG_ECMA_COMPACT_PROFILE_DISABLE_REGEXP_BUILTIN */
#endif /* !RE_PARSER_H */