/** * 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 < tree->var_decls_cout; 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 */
//for debugging . returns black_height int assert_tree(ptr_rbnode node) { if (node == NULL) return 0; if (node->parent) { assert(!( (node->color == RED) && (node->parent->color == RED) )); } int left_bh = 0, right_bh = 0; if (node->left) left_bh = assert_tree(node->left); if (node->right) right_bh = assert_tree(node->right); assert(left_bh == right_bh); return left_bh + (node->color == BLACK ? 1 : 0); }
/** * 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 */
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); }
/* 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 >= sizeof (insts_data_header_t) + (size_t) (scopes_tree_count_instructions (tree)) * sizeof (vm_instr_t)); insts_data_header_t *opcodes_data = (insts_data_header_t *) buffer_p; memset (opcodes_data, 0, instructions_array_size); vm_instr_t *instrs = (vm_instr_t *)(((uint8_t*) opcodes_data) + sizeof (insts_data_header_t)); 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; } MEM_CP_SET_POINTER (opcodes_data->lit_id_hash_cp, lit_ids); return instrs; } /* scopes_tree_raw_data */
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); }
/** * 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, tree->var_decls_cout++, &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 < tree->var_decls_cout); return *(op_meta *) linked_list_element (tree->var_decls, oc); } /* scopes_tree_var_decl */
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 + t->var_decls_cout); 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; }
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->instrs); linked_list_free (tree->var_decls); jsp_mm_free (tree); }
/* * 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 < tree->var_decls_cout; 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 */
bool scopes_tree_strict_mode (scopes_tree tree) { assert_tree (tree); return (bool) tree->strict_mode; }
/** * 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 "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 */
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); }
/** * 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 t->var_decls_cout; } /* scopes_tree_var_decls_num */
vm_instr_counter_t scopes_tree_instrs_num (scopes_tree t) { assert_tree (t); return t->instrs_count; }