mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
JerryScript-DCO-1.0-Signed-off-by: Evgeny Gavrin e.gavrin@samsung.com JerryScript-DCO-1.0-Signed-off-by: Andrey Shitov a.shitov@samsung.com
682 lines
18 KiB
C++
682 lines
18 KiB
C++
/* 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 "scopes-tree.h"
|
|
#include "bytecode-data.h"
|
|
|
|
#define OPCODE(op) (__op__idx_##op)
|
|
#define HASH_SIZE 128
|
|
|
|
static hash_table lit_id_to_uid = null_hash;
|
|
static opcode_counter_t global_oc;
|
|
static idx_t next_uid;
|
|
|
|
static void
|
|
assert_tree (scopes_tree t)
|
|
{
|
|
JERRY_ASSERT (t != NULL);
|
|
}
|
|
|
|
static idx_t
|
|
get_uid (op_meta *op, uint8_t i)
|
|
{
|
|
JERRY_ASSERT (i < 4);
|
|
raw_opcode *raw = (raw_opcode *) &op->op;
|
|
return raw->uids[i + 1];
|
|
}
|
|
|
|
static void
|
|
set_uid (op_meta *op, uint8_t i, idx_t uid)
|
|
{
|
|
JERRY_ASSERT (i < 4);
|
|
raw_opcode *raw = (raw_opcode *) &op->op;
|
|
raw->uids[i + 1] = uid;
|
|
}
|
|
|
|
opcode_counter_t
|
|
scopes_tree_opcodes_num (scopes_tree t)
|
|
{
|
|
assert_tree (t);
|
|
return t->opcodes_num;
|
|
}
|
|
|
|
void
|
|
scopes_tree_add_op_meta (scopes_tree tree, op_meta op)
|
|
{
|
|
assert_tree (tree);
|
|
linked_list_set_element (tree->opcodes, tree->opcodes_num++, &op);
|
|
}
|
|
|
|
void
|
|
scopes_tree_set_op_meta (scopes_tree tree, opcode_counter_t oc, op_meta op)
|
|
{
|
|
assert_tree (tree);
|
|
JERRY_ASSERT (oc < tree->opcodes_num);
|
|
linked_list_set_element (tree->opcodes, oc, &op);
|
|
}
|
|
|
|
void
|
|
scopes_tree_set_opcodes_num (scopes_tree tree, opcode_counter_t oc)
|
|
{
|
|
assert_tree (tree);
|
|
JERRY_ASSERT (oc < tree->opcodes_num);
|
|
tree->opcodes_num = oc;
|
|
}
|
|
|
|
op_meta
|
|
scopes_tree_op_meta (scopes_tree tree, opcode_counter_t oc)
|
|
{
|
|
assert_tree (tree);
|
|
JERRY_ASSERT (oc < tree->opcodes_num);
|
|
return *(op_meta *) linked_list_element (tree->opcodes, oc);
|
|
}
|
|
|
|
opcode_counter_t
|
|
scopes_tree_count_opcodes (scopes_tree t)
|
|
{
|
|
assert_tree (t);
|
|
opcode_counter_t res = t->opcodes_num;
|
|
for (uint8_t i = 0; i < t->t.children_num; i++)
|
|
{
|
|
res = (opcode_counter_t) (
|
|
res + scopes_tree_count_opcodes (
|
|
*(scopes_tree *) linked_list_element (t->t.children, i)));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
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 (idx_t), HASH_SIZE, lit_id_hash,
|
|
MEM_HEAP_ALLOC_SHORT_TERM);
|
|
}
|
|
}
|
|
|
|
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) == LITERAL_TO_REWRITE)
|
|
{
|
|
JERRY_ASSERT (om->lit_id[i].packed_value != MEM_CP_NULL);
|
|
lit_cpointer_t lit_id = om->lit_id[i];
|
|
idx_t *uid = (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 = (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) == LITERAL_TO_REWRITE)
|
|
{
|
|
JERRY_ASSERT (om->lit_id[i].packed_value != MEM_CP_NULL);
|
|
lit_cpointer_t lit_id = om->lit_id[i];
|
|
idx_t *uid = (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 = (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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static op_meta *
|
|
extract_op_meta (scopes_tree tree, opcode_counter_t opc_index)
|
|
{
|
|
return (op_meta *) linked_list_element (tree->opcodes, opc_index);
|
|
}
|
|
|
|
static opcode_t
|
|
generate_opcode (scopes_tree tree, opcode_counter_t opc_index, lit_id_hash_table *lit_ids)
|
|
{
|
|
start_new_block_if_necessary ();
|
|
op_meta *om = extract_op_meta (tree, opc_index);
|
|
/* Now we should change uids of opcodes.
|
|
Since different opcodes 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->op.op_idx)
|
|
{
|
|
case OPCODE (prop_getter):
|
|
case OPCODE (prop_setter):
|
|
case OPCODE (delete_prop):
|
|
case OPCODE (b_shift_left):
|
|
case OPCODE (b_shift_right):
|
|
case OPCODE (b_shift_uright):
|
|
case OPCODE (b_and):
|
|
case OPCODE (b_or):
|
|
case OPCODE (b_xor):
|
|
case OPCODE (equal_value):
|
|
case OPCODE (not_equal_value):
|
|
case OPCODE (equal_value_type):
|
|
case OPCODE (not_equal_value_type):
|
|
case OPCODE (less_than):
|
|
case OPCODE (greater_than):
|
|
case OPCODE (less_or_equal_than):
|
|
case OPCODE (greater_or_equal_than):
|
|
case OPCODE (instanceof):
|
|
case OPCODE (in):
|
|
case OPCODE (addition):
|
|
case OPCODE (substraction):
|
|
case OPCODE (division):
|
|
case OPCODE (multiplication):
|
|
case OPCODE (remainder):
|
|
{
|
|
change_uid (om, lit_ids, 0x111);
|
|
break;
|
|
}
|
|
case OPCODE (call_n):
|
|
case OPCODE (native_call):
|
|
case OPCODE (construct_n):
|
|
case OPCODE (func_expr_n):
|
|
case OPCODE (delete_var):
|
|
case OPCODE (typeof):
|
|
case OPCODE (b_not):
|
|
case OPCODE (logical_not):
|
|
case OPCODE (post_incr):
|
|
case OPCODE (post_decr):
|
|
case OPCODE (pre_incr):
|
|
case OPCODE (pre_decr):
|
|
case OPCODE (unary_plus):
|
|
case OPCODE (unary_minus):
|
|
{
|
|
change_uid (om, lit_ids, 0x110);
|
|
break;
|
|
}
|
|
case OPCODE (assignment):
|
|
{
|
|
switch (om->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, lit_ids, 0x100);
|
|
break;
|
|
}
|
|
case OPCODE_ARG_TYPE_NUMBER:
|
|
case OPCODE_ARG_TYPE_NUMBER_NEGATE:
|
|
case OPCODE_ARG_TYPE_STRING:
|
|
case OPCODE_ARG_TYPE_VARIABLE:
|
|
{
|
|
change_uid (om, lit_ids, 0x101);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case OPCODE (func_decl_n):
|
|
case OPCODE (array_decl):
|
|
case OPCODE (obj_decl):
|
|
case OPCODE (this_binding):
|
|
case OPCODE (with):
|
|
case OPCODE (throw_value):
|
|
case OPCODE (is_true_jmp_up):
|
|
case OPCODE (is_true_jmp_down):
|
|
case OPCODE (is_false_jmp_up):
|
|
case OPCODE (is_false_jmp_down):
|
|
case OPCODE (var_decl):
|
|
case OPCODE (retval):
|
|
{
|
|
change_uid (om, lit_ids, 0x100);
|
|
break;
|
|
}
|
|
case OPCODE (exitval):
|
|
case OPCODE (ret):
|
|
case OPCODE (try_block):
|
|
case OPCODE (jmp_up):
|
|
case OPCODE (jmp_down):
|
|
case OPCODE (nop):
|
|
case OPCODE (reg_var_decl):
|
|
{
|
|
change_uid (om, lit_ids, 0x000);
|
|
break;
|
|
}
|
|
case OPCODE (meta):
|
|
{
|
|
switch (om->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, lit_ids, 0x011);
|
|
break;
|
|
}
|
|
case OPCODE_META_TYPE_THIS_ARG:
|
|
case OPCODE_META_TYPE_VARG:
|
|
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
|
|
{
|
|
change_uid (om, 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_SCOPE_CODE_FLAGS:
|
|
{
|
|
change_uid (om, lit_ids, 0x000);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return om->op;
|
|
}
|
|
|
|
static idx_t
|
|
count_new_literals_in_opcode (scopes_tree tree, opcode_counter_t opc_index)
|
|
{
|
|
start_new_block_if_necessary ();
|
|
idx_t current_uid = next_uid;
|
|
op_meta *om = extract_op_meta (tree, opc_index);
|
|
switch (om->op.op_idx)
|
|
{
|
|
case OPCODE (prop_getter):
|
|
case OPCODE (prop_setter):
|
|
case OPCODE (delete_prop):
|
|
case OPCODE (b_shift_left):
|
|
case OPCODE (b_shift_right):
|
|
case OPCODE (b_shift_uright):
|
|
case OPCODE (b_and):
|
|
case OPCODE (b_or):
|
|
case OPCODE (b_xor):
|
|
case OPCODE (equal_value):
|
|
case OPCODE (not_equal_value):
|
|
case OPCODE (equal_value_type):
|
|
case OPCODE (not_equal_value_type):
|
|
case OPCODE (less_than):
|
|
case OPCODE (greater_than):
|
|
case OPCODE (less_or_equal_than):
|
|
case OPCODE (greater_or_equal_than):
|
|
case OPCODE (instanceof):
|
|
case OPCODE (in):
|
|
case OPCODE (addition):
|
|
case OPCODE (substraction):
|
|
case OPCODE (division):
|
|
case OPCODE (multiplication):
|
|
case OPCODE (remainder):
|
|
{
|
|
insert_uids_to_lit_id_map (om, 0x111);
|
|
break;
|
|
}
|
|
case OPCODE (call_n):
|
|
case OPCODE (native_call):
|
|
case OPCODE (construct_n):
|
|
case OPCODE (func_expr_n):
|
|
case OPCODE (delete_var):
|
|
case OPCODE (typeof):
|
|
case OPCODE (b_not):
|
|
case OPCODE (logical_not):
|
|
case OPCODE (post_incr):
|
|
case OPCODE (post_decr):
|
|
case OPCODE (pre_incr):
|
|
case OPCODE (pre_decr):
|
|
case OPCODE (unary_plus):
|
|
case OPCODE (unary_minus):
|
|
{
|
|
insert_uids_to_lit_id_map (om, 0x110);
|
|
break;
|
|
}
|
|
case OPCODE (assignment):
|
|
{
|
|
switch (om->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, 0x100);
|
|
break;
|
|
}
|
|
case OPCODE_ARG_TYPE_NUMBER:
|
|
case OPCODE_ARG_TYPE_NUMBER_NEGATE:
|
|
case OPCODE_ARG_TYPE_STRING:
|
|
case OPCODE_ARG_TYPE_VARIABLE:
|
|
{
|
|
insert_uids_to_lit_id_map (om, 0x101);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case OPCODE (func_decl_n):
|
|
case OPCODE (array_decl):
|
|
case OPCODE (obj_decl):
|
|
case OPCODE (this_binding):
|
|
case OPCODE (with):
|
|
case OPCODE (throw_value):
|
|
case OPCODE (is_true_jmp_up):
|
|
case OPCODE (is_true_jmp_down):
|
|
case OPCODE (is_false_jmp_up):
|
|
case OPCODE (is_false_jmp_down):
|
|
case OPCODE (var_decl):
|
|
case OPCODE (retval):
|
|
{
|
|
insert_uids_to_lit_id_map (om, 0x100);
|
|
break;
|
|
}
|
|
case OPCODE (exitval):
|
|
case OPCODE (ret):
|
|
case OPCODE (try_block):
|
|
case OPCODE (jmp_up):
|
|
case OPCODE (jmp_down):
|
|
case OPCODE (nop):
|
|
case OPCODE (reg_var_decl):
|
|
{
|
|
insert_uids_to_lit_id_map (om, 0x000);
|
|
break;
|
|
}
|
|
case OPCODE (meta):
|
|
{
|
|
switch (om->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, 0x011);
|
|
break;
|
|
}
|
|
case OPCODE_META_TYPE_THIS_ARG:
|
|
case OPCODE_META_TYPE_VARG:
|
|
case OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER:
|
|
{
|
|
insert_uids_to_lit_id_map (om, 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_SCOPE_CODE_FLAGS:
|
|
{
|
|
insert_uids_to_lit_id_map (om, 0x000);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return (idx_t) (next_uid - current_uid);
|
|
}
|
|
|
|
/* 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. */
|
|
size_t
|
|
scopes_tree_count_literals_in_blocks (scopes_tree tree)
|
|
{
|
|
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);
|
|
opcode_counter_t opc_index;
|
|
bool header = true;
|
|
for (opc_index = 0; opc_index < tree->opcodes_num; opc_index++)
|
|
{
|
|
op_meta *om = extract_op_meta (tree, opc_index);
|
|
if (om->op.op_idx != OPCODE (var_decl)
|
|
&& om->op.op_idx != OPCODE (meta) && !header)
|
|
{
|
|
break;
|
|
}
|
|
if (om->op.op_idx == OPCODE (reg_var_decl))
|
|
{
|
|
header = false;
|
|
}
|
|
result += count_new_literals_in_opcode (tree, opc_index);
|
|
}
|
|
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 (; opc_index < tree->opcodes_num; opc_index++)
|
|
{
|
|
result += count_new_literals_in_opcode (tree, opc_index);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* 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 opcodes.
|
|
|
|
For each opcodes block (size of block is defined in bytecode-data.h)
|
|
literal indexes 'hash' table is filled. */
|
|
static void
|
|
merge_subscopes (scopes_tree tree, opcode_t *data, lit_id_hash_table *lit_ids)
|
|
{
|
|
assert_tree (tree);
|
|
JERRY_ASSERT (data);
|
|
opcode_counter_t opc_index;
|
|
bool header = true;
|
|
for (opc_index = 0; opc_index < tree->opcodes_num; opc_index++)
|
|
{
|
|
op_meta *om = extract_op_meta (tree, opc_index);
|
|
if (om->op.op_idx != OPCODE (var_decl)
|
|
&& om->op.op_idx != OPCODE (meta) && !header)
|
|
{
|
|
break;
|
|
}
|
|
if (om->op.op_idx == OPCODE (reg_var_decl))
|
|
{
|
|
header = false;
|
|
}
|
|
data[global_oc] = generate_opcode (tree, opc_index, lit_ids);
|
|
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, lit_ids);
|
|
}
|
|
for (; opc_index < tree->opcodes_num; opc_index++)
|
|
{
|
|
data[global_oc] = generate_opcode (tree, opc_index, lit_ids);
|
|
global_oc++;
|
|
}
|
|
}
|
|
|
|
/* Postparser.
|
|
Init literal indexes 'hash' table.
|
|
Reorder function declarations.
|
|
Rewrite opcodes' temporary uids with their keys in literal indexes 'hash' table. */
|
|
opcode_t *
|
|
scopes_tree_raw_data (scopes_tree tree, lit_id_hash_table *lit_ids)
|
|
{
|
|
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. */
|
|
size_t size = ((size_t) (scopes_tree_count_opcodes (tree) + 1) * sizeof (opcode_t)); // +1 for valgrind
|
|
opcode_t *opcodes = (opcode_t *) mem_heap_alloc_block (size, MEM_HEAP_ALLOC_LONG_TERM);
|
|
memset (opcodes, 0, size);
|
|
merge_subscopes (tree, opcodes, lit_ids);
|
|
if (lit_id_to_uid != null_hash)
|
|
{
|
|
hash_table_free (lit_id_to_uid);
|
|
lit_id_to_uid = null_hash;
|
|
}
|
|
return opcodes;
|
|
}
|
|
|
|
void
|
|
scopes_tree_set_strict_mode (scopes_tree tree, bool strict_mode)
|
|
{
|
|
assert_tree (tree);
|
|
tree->strict_mode = strict_mode ? 1 : 0;
|
|
}
|
|
|
|
bool
|
|
scopes_tree_strict_mode (scopes_tree tree)
|
|
{
|
|
assert_tree (tree);
|
|
return (bool) tree->strict_mode;
|
|
}
|
|
|
|
scopes_tree
|
|
scopes_tree_init (scopes_tree parent)
|
|
{
|
|
scopes_tree tree = (scopes_tree) mem_heap_alloc_block (sizeof (scopes_tree_int), MEM_HEAP_ALLOC_SHORT_TERM);
|
|
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->opcodes_num = 0;
|
|
tree->strict_mode = 0;
|
|
tree->opcodes = linked_list_init (sizeof (op_meta));
|
|
return tree;
|
|
}
|
|
|
|
void
|
|
scopes_tree_free (scopes_tree tree)
|
|
{
|
|
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->opcodes);
|
|
mem_heap_free_block ((uint8_t *) tree);
|
|
}
|