Parser optimizations.

- parser is now non-recursive (i.e. parse function is not called recursively in any case);
 - byte-code is now more compact:
    - constants are now not immediately dumped upon occurence, but later - where necessary;
    - assignments are combined with unary / binary operations;
    - binary operations are encoded more compactly in many cases;
 - byte-code arrays are now allocated separately for each scope (so, GC of the scopes now becomes possible);
 - byte-code is dumped directly into corresponding byte-code arrays:
   - linked lists of op_meta are not now used for main code of a scope.

JerryScript-DCO-1.0-Signed-off-by: Ruben Ayrapetyan r.ayrapetyan@samsung.com
JerryScript-DCO-1.0-Signed-off-by: Andrey Shitov a.shitov@samsung.com
This commit is contained in:
Andrey Shitov
2015-11-03 19:14:19 +03:00
committed by Ruben Ayrapetyan
parent b1de93abd6
commit 50d124bfc3
51 changed files with 9044 additions and 7401 deletions
+91 -681
View File
@@ -17,11 +17,8 @@
#include "jsp-mm.h"
#include "scopes-tree.h"
#define HASH_SIZE 128
static hash_table lit_id_to_uid = null_hash;
static vm_instr_counter_t global_oc;
static vm_idx_t next_uid;
scopes_tree scopes_tree_root_node_p = NULL;
scopes_tree scopes_tree_last_node_p = NULL;
static void
assert_tree (scopes_tree t)
@@ -29,20 +26,6 @@ assert_tree (scopes_tree t)
JERRY_ASSERT (t != NULL);
}
static vm_idx_t
get_uid (op_meta *op, size_t i)
{
JERRY_ASSERT (i < 3);
return op->op.data.raw_args[i];
}
static void
set_uid (op_meta *op, size_t i, vm_idx_t uid)
{
JERRY_ASSERT (i < 3);
op->op.data.raw_args[i] = uid;
}
vm_instr_counter_t
scopes_tree_instrs_num (scopes_tree t)
{
@@ -62,13 +45,6 @@ scopes_tree_var_decls_num (scopes_tree t) /**< scope */
return linked_list_get_length (t->var_decls);
} /* scopes_tree_var_decls_num */
void
scopes_tree_add_op_meta (scopes_tree tree, op_meta op)
{
assert_tree (tree);
linked_list_set_element (tree->instrs, tree->instrs_count++, &op);
}
/**
* Add variable declaration to a scope
*/
@@ -80,30 +56,6 @@ scopes_tree_add_var_decl (scopes_tree tree, /**< scope, to which variable declar
linked_list_set_element (tree->var_decls, linked_list_get_length (tree->var_decls), &op);
} /* scopes_tree_add_var_decl */
void
scopes_tree_set_op_meta (scopes_tree tree, vm_instr_counter_t oc, op_meta op)
{
assert_tree (tree);
JERRY_ASSERT (oc < tree->instrs_count);
linked_list_set_element (tree->instrs, oc, &op);
}
void
scopes_tree_set_instrs_num (scopes_tree tree, vm_instr_counter_t oc)
{
assert_tree (tree);
JERRY_ASSERT (oc < tree->instrs_count);
tree->instrs_count = oc;
}
op_meta
scopes_tree_op_meta (scopes_tree tree, vm_instr_counter_t oc)
{
assert_tree (tree);
JERRY_ASSERT (oc < tree->instrs_count);
return *(op_meta *) linked_list_element (tree->instrs, oc);
}
/**
* Get variable declaration for the specified scope
*
@@ -118,34 +70,6 @@ scopes_tree_var_decl (scopes_tree tree, /**< scope, from which variable declarat
return *(op_meta *) linked_list_element (tree->var_decls, oc);
} /* scopes_tree_var_decl */
/**
* Remove specified instruction from scopes tree node's instructions list
*/
void
scopes_tree_remove_op_meta (scopes_tree tree, /**< scopes tree node */
vm_instr_counter_t oc) /**< position of instruction to remove */
{
assert_tree (tree);
JERRY_ASSERT (oc < tree->instrs_count);
linked_list_remove_element (tree->instrs, oc);
tree->instrs_count--;
} /* scopes_tree_remove_op_meta */
vm_instr_counter_t
scopes_tree_count_instructions (scopes_tree t)
{
assert_tree (t);
vm_instr_counter_t res = (vm_instr_counter_t) (t->instrs_count + linked_list_get_length (t->var_decls));
for (uint8_t i = 0; i < t->t.children_num; i++)
{
res = (vm_instr_counter_t) (
res + scopes_tree_count_instructions (
*(scopes_tree *) linked_list_element (t->t.children, i)));
}
return res;
}
/**
* Checks if variable declaration exists in the scope
*
@@ -175,581 +99,20 @@ scopes_tree_variable_declaration_exists (scopes_tree tree, /**< scope */
return false;
} /* scopes_tree_variable_declaration_exists */
static uint16_t
lit_id_hash (void * lit_id)
{
return ((lit_cpointer_t *) lit_id)->packed_value % HASH_SIZE;
}
static void
start_new_block_if_necessary (void)
{
if (global_oc % BLOCK_SIZE == 0)
{
next_uid = 0;
if (lit_id_to_uid != null_hash)
{
hash_table_free (lit_id_to_uid);
lit_id_to_uid = null_hash;
}
lit_id_to_uid = hash_table_init (sizeof (lit_cpointer_t), sizeof (vm_idx_t), HASH_SIZE, lit_id_hash);
}
}
static bool
is_possible_literal (uint16_t mask, uint8_t index)
{
int res;
switch (index)
{
case 0:
{
res = mask >> 8;
break;
}
case 1:
{
res = (mask & 0xF0) >> 4;
break;
}
default:
{
JERRY_ASSERT (index = 2);
res = mask & 0x0F;
}
}
JERRY_ASSERT (res == 0 || res == 1);
return res == 1;
}
static void
change_uid (op_meta *om, lit_id_hash_table *lit_ids, uint16_t mask)
{
for (uint8_t i = 0; i < 3; i++)
{
if (is_possible_literal (mask, i))
{
if (get_uid (om, i) == VM_IDX_REWRITE_LITERAL_UID)
{
JERRY_ASSERT (om->lit_id[i].packed_value != MEM_CP_NULL);
lit_cpointer_t lit_id = om->lit_id[i];
vm_idx_t *uid = (vm_idx_t *) hash_table_lookup (lit_id_to_uid, &lit_id);
if (uid == NULL)
{
hash_table_insert (lit_id_to_uid, &lit_id, &next_uid);
lit_id_hash_table_insert (lit_ids, next_uid, global_oc, lit_id);
uid = (vm_idx_t *) hash_table_lookup (lit_id_to_uid, &lit_id);
JERRY_ASSERT (uid != NULL);
JERRY_ASSERT (*uid == next_uid);
next_uid++;
}
set_uid (om, i, *uid);
}
else
{
JERRY_ASSERT (om->lit_id[i].packed_value == MEM_CP_NULL);
}
}
else
{
JERRY_ASSERT (om->lit_id[i].packed_value == MEM_CP_NULL);
}
}
}
static void
insert_uids_to_lit_id_map (op_meta *om, uint16_t mask)
{
for (uint8_t i = 0; i < 3; i++)
{
if (is_possible_literal (mask, i))
{
if (get_uid (om, i) == VM_IDX_REWRITE_LITERAL_UID)
{
JERRY_ASSERT (om->lit_id[i].packed_value != MEM_CP_NULL);
lit_cpointer_t lit_id = om->lit_id[i];
vm_idx_t *uid = (vm_idx_t *) hash_table_lookup (lit_id_to_uid, &lit_id);
if (uid == NULL)
{
hash_table_insert (lit_id_to_uid, &lit_id, &next_uid);
uid = (vm_idx_t *) hash_table_lookup (lit_id_to_uid, &lit_id);
JERRY_ASSERT (uid != NULL);
JERRY_ASSERT (*uid == next_uid);
next_uid++;
}
}
else
{
JERRY_ASSERT (om->lit_id[i].packed_value == MEM_CP_NULL);
}
}
else
{
JERRY_ASSERT (om->lit_id[i].packed_value == MEM_CP_NULL);
}
}
}
/**
* Get instruction from instruction list
*
* @return instruction at specified position
* Fill variable declaration list of bytecode header
*/
static op_meta *
extract_op_meta (linked_list instr_list, /**< instruction list */
vm_instr_counter_t instr_pos) /**< position inside the list */
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 */
{
return (op_meta *) linked_list_element (instr_list, instr_pos);
} /* extract_op_meta */
/**
* Add instruction to an instruction list
*
* @return generated instruction
*/
static vm_instr_t
generate_instr (linked_list instr_list, /**< instruction list */
vm_instr_counter_t instr_pos, /**< position where to generate an instruction */
lit_id_hash_table *lit_ids) /**< hash table binding operand identifiers and literals */
{
start_new_block_if_necessary ();
op_meta *om_p = extract_op_meta (instr_list, instr_pos);
/* Now we should change uids of instructions.
Since different instructions has different literals/tmps in different places,
we should change only them.
For each case possible literal positions are shown as 0xYYY literal,
where Y is set to '1' when there is a possible literal in this position,
and '0' otherwise. */
switch (om_p->op.op_idx)
for (uint32_t i = 0; i < scopes_tree_var_decls_num (scope); ++i)
{
case VM_OP_PROP_GETTER:
case VM_OP_PROP_SETTER:
case VM_OP_DELETE_PROP:
case VM_OP_B_SHIFT_LEFT:
case VM_OP_B_SHIFT_RIGHT:
case VM_OP_B_SHIFT_URIGHT:
case VM_OP_B_AND:
case VM_OP_B_OR:
case VM_OP_B_XOR:
case VM_OP_EQUAL_VALUE:
case VM_OP_NOT_EQUAL_VALUE:
case VM_OP_EQUAL_VALUE_TYPE:
case VM_OP_NOT_EQUAL_VALUE_TYPE:
case VM_OP_LESS_THAN:
case VM_OP_GREATER_THAN:
case VM_OP_LESS_OR_EQUAL_THAN:
case VM_OP_GREATER_OR_EQUAL_THAN:
case VM_OP_INSTANCEOF:
case VM_OP_IN:
case VM_OP_ADDITION:
case VM_OP_SUBSTRACTION:
case VM_OP_DIVISION:
case VM_OP_MULTIPLICATION:
case VM_OP_REMAINDER:
{
change_uid (om_p, lit_ids, 0x111);
break;
}
case VM_OP_CALL_N:
case VM_OP_CONSTRUCT_N:
case VM_OP_FUNC_EXPR_N:
case VM_OP_DELETE_VAR:
case VM_OP_TYPEOF:
case VM_OP_B_NOT:
case VM_OP_LOGICAL_NOT:
case VM_OP_POST_INCR:
case VM_OP_POST_DECR:
case VM_OP_PRE_INCR:
case VM_OP_PRE_DECR:
case VM_OP_UNARY_PLUS:
case VM_OP_UNARY_MINUS:
{
change_uid (om_p, lit_ids, 0x110);
break;
}
case VM_OP_ASSIGNMENT:
{
switch (om_p->op.data.assignment.type_value_right)
{
case OPCODE_ARG_TYPE_SIMPLE:
case OPCODE_ARG_TYPE_SMALLINT:
case OPCODE_ARG_TYPE_SMALLINT_NEGATE:
{
change_uid (om_p, lit_ids, 0x100);
break;
}
case OPCODE_ARG_TYPE_NUMBER:
case OPCODE_ARG_TYPE_NUMBER_NEGATE:
case OPCODE_ARG_TYPE_REGEXP:
case OPCODE_ARG_TYPE_STRING:
case OPCODE_ARG_TYPE_VARIABLE:
{
change_uid (om_p, lit_ids, 0x101);
break;
}
}
break;
}
case VM_OP_FUNC_DECL_N:
case VM_OP_ARRAY_DECL:
case VM_OP_OBJ_DECL:
case VM_OP_WITH:
case VM_OP_FOR_IN:
case VM_OP_THROW_VALUE:
case VM_OP_IS_TRUE_JMP_UP:
case VM_OP_IS_TRUE_JMP_DOWN:
case VM_OP_IS_FALSE_JMP_UP:
case VM_OP_IS_FALSE_JMP_DOWN:
case VM_OP_VAR_DECL:
case VM_OP_RETVAL:
{
change_uid (om_p, lit_ids, 0x100);
break;
}
case VM_OP_RET:
case VM_OP_TRY_BLOCK:
case VM_OP_JMP_UP:
case VM_OP_JMP_DOWN:
case VM_OP_REG_VAR_DECL:
{
change_uid (om_p, lit_ids, 0x000);
break;
}
case VM_OP_META:
{
switch (om_p->op.data.meta.type)
{
case OPCODE_META_TYPE_VARG_PROP_DATA:
case OPCODE_META_TYPE_VARG_PROP_GETTER:
case OPCODE_META_TYPE_VARG_PROP_SETTER:
{
change_uid (om_p, lit_ids, 0x011);
break;
}
case OPCODE_META_TYPE_VARG:
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
{
change_uid (om_p, lit_ids, 0x010);
break;
}
case OPCODE_META_TYPE_UNDEFINED:
case OPCODE_META_TYPE_END_WITH:
case OPCODE_META_TYPE_FUNCTION_END:
case OPCODE_META_TYPE_CATCH:
case OPCODE_META_TYPE_FINALLY:
case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY:
case OPCODE_META_TYPE_CALL_SITE_INFO:
case OPCODE_META_TYPE_SCOPE_CODE_FLAGS:
{
change_uid (om_p, lit_ids, 0x000);
break;
}
}
break;
}
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];
}
return om_p->op;
} /* generate_instr */
/**
* Count number of literals in instruction which were not seen previously
*
* @return number of new literals
*/
static vm_idx_t
count_new_literals_in_instr (op_meta *om_p) /**< instruction */
{
start_new_block_if_necessary ();
vm_idx_t current_uid = next_uid;
switch (om_p->op.op_idx)
{
case VM_OP_PROP_GETTER:
case VM_OP_PROP_SETTER:
case VM_OP_DELETE_PROP:
case VM_OP_B_SHIFT_LEFT:
case VM_OP_B_SHIFT_RIGHT:
case VM_OP_B_SHIFT_URIGHT:
case VM_OP_B_AND:
case VM_OP_B_OR:
case VM_OP_B_XOR:
case VM_OP_EQUAL_VALUE:
case VM_OP_NOT_EQUAL_VALUE:
case VM_OP_EQUAL_VALUE_TYPE:
case VM_OP_NOT_EQUAL_VALUE_TYPE:
case VM_OP_LESS_THAN:
case VM_OP_GREATER_THAN:
case VM_OP_LESS_OR_EQUAL_THAN:
case VM_OP_GREATER_OR_EQUAL_THAN:
case VM_OP_INSTANCEOF:
case VM_OP_IN:
case VM_OP_ADDITION:
case VM_OP_SUBSTRACTION:
case VM_OP_DIVISION:
case VM_OP_MULTIPLICATION:
case VM_OP_REMAINDER:
{
insert_uids_to_lit_id_map (om_p, 0x111);
break;
}
case VM_OP_CALL_N:
case VM_OP_CONSTRUCT_N:
case VM_OP_FUNC_EXPR_N:
case VM_OP_DELETE_VAR:
case VM_OP_TYPEOF:
case VM_OP_B_NOT:
case VM_OP_LOGICAL_NOT:
case VM_OP_POST_INCR:
case VM_OP_POST_DECR:
case VM_OP_PRE_INCR:
case VM_OP_PRE_DECR:
case VM_OP_UNARY_PLUS:
case VM_OP_UNARY_MINUS:
{
insert_uids_to_lit_id_map (om_p, 0x110);
break;
}
case VM_OP_ASSIGNMENT:
{
switch (om_p->op.data.assignment.type_value_right)
{
case OPCODE_ARG_TYPE_SIMPLE:
case OPCODE_ARG_TYPE_SMALLINT:
case OPCODE_ARG_TYPE_SMALLINT_NEGATE:
{
insert_uids_to_lit_id_map (om_p, 0x100);
break;
}
case OPCODE_ARG_TYPE_NUMBER:
case OPCODE_ARG_TYPE_NUMBER_NEGATE:
case OPCODE_ARG_TYPE_REGEXP:
case OPCODE_ARG_TYPE_STRING:
case OPCODE_ARG_TYPE_VARIABLE:
{
insert_uids_to_lit_id_map (om_p, 0x101);
break;
}
}
break;
}
case VM_OP_FUNC_DECL_N:
case VM_OP_ARRAY_DECL:
case VM_OP_OBJ_DECL:
case VM_OP_WITH:
case VM_OP_THROW_VALUE:
case VM_OP_IS_TRUE_JMP_UP:
case VM_OP_IS_TRUE_JMP_DOWN:
case VM_OP_IS_FALSE_JMP_UP:
case VM_OP_IS_FALSE_JMP_DOWN:
case VM_OP_VAR_DECL:
case VM_OP_RETVAL:
{
insert_uids_to_lit_id_map (om_p, 0x100);
break;
}
case VM_OP_RET:
case VM_OP_TRY_BLOCK:
case VM_OP_JMP_UP:
case VM_OP_JMP_DOWN:
case VM_OP_REG_VAR_DECL:
{
insert_uids_to_lit_id_map (om_p, 0x000);
break;
}
case VM_OP_META:
{
switch (om_p->op.data.meta.type)
{
case OPCODE_META_TYPE_VARG_PROP_DATA:
case OPCODE_META_TYPE_VARG_PROP_GETTER:
case OPCODE_META_TYPE_VARG_PROP_SETTER:
{
insert_uids_to_lit_id_map (om_p, 0x011);
break;
}
case OPCODE_META_TYPE_VARG:
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
{
insert_uids_to_lit_id_map (om_p, 0x010);
break;
}
case OPCODE_META_TYPE_UNDEFINED:
case OPCODE_META_TYPE_END_WITH:
case OPCODE_META_TYPE_FUNCTION_END:
case OPCODE_META_TYPE_CATCH:
case OPCODE_META_TYPE_FINALLY:
case OPCODE_META_TYPE_END_TRY_CATCH_FINALLY:
case OPCODE_META_TYPE_CALL_SITE_INFO:
case OPCODE_META_TYPE_SCOPE_CODE_FLAGS:
{
insert_uids_to_lit_id_map (om_p, 0x000);
break;
}
}
break;
}
}
return (vm_idx_t) (next_uid - current_uid);
} /* count_new_literals_in_instr */
/**
* Count slots needed for a scope's hash table
*
* Before filling literal indexes 'hash' table we shall initiate it with number of neccesary literal indexes.
* Since bytecode is divided into blocks and id of the block is a part of hash key, we shall divide bytecode
* into blocks and count unique literal indexes used in each block.
*
* @return total number of literals in scope
*/
size_t
scopes_tree_count_literals_in_blocks (scopes_tree tree) /**< scope */
{
assert_tree (tree);
size_t result = 0;
if (lit_id_to_uid != null_hash)
{
hash_table_free (lit_id_to_uid);
lit_id_to_uid = null_hash;
}
next_uid = 0;
global_oc = 0;
assert_tree (tree);
vm_instr_counter_t instr_pos;
bool header = true;
for (instr_pos = 0; instr_pos < tree->instrs_count; instr_pos++)
{
op_meta *om_p = extract_op_meta (tree->instrs, instr_pos);
if (om_p->op.op_idx != VM_OP_META && !header)
{
break;
}
if (om_p->op.op_idx == VM_OP_REG_VAR_DECL)
{
header = false;
}
result += count_new_literals_in_instr (om_p);
}
for (vm_instr_counter_t var_decl_pos = 0;
var_decl_pos < linked_list_get_length (tree->var_decls);
var_decl_pos++)
{
op_meta *om_p = extract_op_meta (tree->var_decls, var_decl_pos);
result += count_new_literals_in_instr (om_p);
}
for (uint8_t child_id = 0; child_id < tree->t.children_num; child_id++)
{
result += scopes_tree_count_literals_in_blocks (*(scopes_tree *) linked_list_element (tree->t.children, child_id));
}
for (; instr_pos < tree->instrs_count; instr_pos++)
{
op_meta *om_p = extract_op_meta (tree->instrs, instr_pos);
result += count_new_literals_in_instr (om_p);
}
return result;
} /* scopes_tree_count_literals_in_blocks */
/*
* This function performs functions hoisting.
*
* Each scope consists of four parts:
* 1) Header with 'use strict' marker and reg_var_decl opcode
* 2) Variable declarations, dumped by the preparser
* 3) Function declarations
* 4) Computational code
*
* Header and var_decls are dumped first,
* then we shall recursively dump function declaration,
* and finally, other instructions.
*
* For each instructions block (size of block is defined in bytecode-data.h)
* literal indexes 'hash' table is filled.
*/
static void
merge_subscopes (scopes_tree tree, /**< scopes tree to merge */
vm_instr_t *data_p, /**< instruction array, where the scopes are merged to */
lit_id_hash_table *lit_ids_p) /**< literal indexes 'hash' table */
{
assert_tree (tree);
JERRY_ASSERT (data_p);
vm_instr_counter_t instr_pos;
bool header = true;
for (instr_pos = 0; instr_pos < tree->instrs_count; instr_pos++)
{
op_meta *om_p = extract_op_meta (tree->instrs, instr_pos);
if (om_p->op.op_idx != VM_OP_VAR_DECL
&& om_p->op.op_idx != VM_OP_META && !header)
{
break;
}
if (om_p->op.op_idx == VM_OP_REG_VAR_DECL)
{
header = false;
}
data_p[global_oc] = generate_instr (tree->instrs, instr_pos, lit_ids_p);
global_oc++;
}
for (vm_instr_counter_t var_decl_pos = 0;
var_decl_pos < linked_list_get_length (tree->var_decls);
var_decl_pos++)
{
data_p[global_oc] = generate_instr (tree->var_decls, var_decl_pos, lit_ids_p);
global_oc++;
}
for (uint8_t child_id = 0; child_id < tree->t.children_num; child_id++)
{
merge_subscopes (*(scopes_tree *) linked_list_element (tree->t.children, child_id),
data_p, lit_ids_p);
}
for (; instr_pos < tree->instrs_count; instr_pos++)
{
data_p[global_oc] = generate_instr (tree->instrs, instr_pos, lit_ids_p);
global_oc++;
}
} /* merge_subscopes */
/* Postparser.
Init literal indexes 'hash' table.
Reorder function declarations.
Rewrite instructions' temporary uids with their keys in literal indexes 'hash' table. */
vm_instr_t *
scopes_tree_raw_data (scopes_tree tree, /**< scopes tree to convert to byte-code array */
uint8_t *buffer_p, /**< buffer for byte-code array and literal identifiers hash table */
size_t instructions_array_size, /**< size of space for byte-code array */
lit_id_hash_table *lit_ids) /**< literal identifiers hash table */
{
JERRY_ASSERT (lit_ids);
assert_tree (tree);
if (lit_id_to_uid != null_hash)
{
hash_table_free (lit_id_to_uid);
lit_id_to_uid = null_hash;
}
next_uid = 0;
global_oc = 0;
/* Dump bytecode and fill literal indexes 'hash' table. */
JERRY_ASSERT (instructions_array_size >= (size_t) (scopes_tree_count_instructions (tree)) * sizeof (vm_instr_t));
vm_instr_t *instrs = (vm_instr_t *) buffer_p;
memset (instrs, 0, instructions_array_size);
merge_subscopes (tree, instrs, lit_ids);
if (lit_id_to_uid != null_hash)
{
hash_table_free (lit_id_to_uid);
lit_id_to_uid = null_hash;
}
return instrs;
} /* scopes_tree_raw_data */
} /* scopes_tree_dump_var_decls */
/**
* Set up a flag, indicating that scope should be executed in strict mode
@@ -829,31 +192,49 @@ scopes_tree_strict_mode (scopes_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_init (scopes_tree parent, /**< parent scope */
scope_type_t type) /**< scope type */
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));
memset (tree, 0, sizeof (scopes_tree_int));
tree->t.parent = (tree_header *) parent;
tree->t.children = null_list;
tree->t.children_num = 0;
if (parent != NULL)
{
if (parent->t.children_num == 0)
{
parent->t.children = linked_list_init (sizeof (scopes_tree));
}
linked_list_set_element (parent->t.children, parent->t.children_num, &tree);
void *added = linked_list_element (parent->t.children, parent->t.children_num);
JERRY_ASSERT (*(scopes_tree *) added == tree);
parent->t.children_num++;
}
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;
@@ -863,24 +244,53 @@ scopes_tree_init (scopes_tree parent, /**< parent scope */
tree->contains_try = false;
tree->contains_delete = false;
tree->contains_functions = false;
tree->instrs = linked_list_init (sizeof (op_meta));
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_init */
} /* scopes_tree_new_scope */
void
scopes_tree_free (scopes_tree tree)
scopes_tree_finish_build (void)
{
assert_tree (tree);
if (tree->t.children_num != 0)
{
for (uint8_t i = 0; i < tree->t.children_num; ++i)
{
scopes_tree_free (*(scopes_tree *) linked_list_element (tree->t.children, i));
}
linked_list_free (tree->t.children);
}
linked_list_free (tree->instrs);
linked_list_free (tree->var_decls);
jsp_mm_free (tree);
}
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 */