/** * Run the code, starting from specified instruction position */ ecma_completion_value_t vm_run_from_pos (const vm_instr_t *instrs_p, /**< byte-code array */ vm_instr_counter_t start_pos, /**< position of starting instruction */ ecma_value_t this_binding_value, /**< value of 'ThisBinding' */ ecma_object_t *lex_env_p, /**< lexical environment to use */ bool is_strict, /**< is the code is strict mode code (ECMA-262 v5, 10.1.1) */ bool is_eval_code) /**< is the code is eval code (ECMA-262 v5, 10.1) */ { ecma_completion_value_t completion; const vm_instr_t *curr = &instrs_p[start_pos]; JERRY_ASSERT (curr->op_idx == VM_OP_REG_VAR_DECL); const idx_t min_reg_num = curr->data.reg_var_decl.min; const idx_t max_reg_num = curr->data.reg_var_decl.max; JERRY_ASSERT (max_reg_num >= min_reg_num); const int32_t regs_num = max_reg_num - min_reg_num + 1; MEM_DEFINE_LOCAL_ARRAY (regs, regs_num, ecma_value_t); vm_frame_ctx_t frame_ctx; frame_ctx.instrs_p = instrs_p; frame_ctx.pos = (vm_instr_counter_t) (start_pos + 1); frame_ctx.this_binding = this_binding_value; frame_ctx.lex_env_p = lex_env_p; frame_ctx.is_strict = is_strict; frame_ctx.is_eval_code = is_eval_code; frame_ctx.is_call_in_direct_eval_form = false; frame_ctx.min_reg_num = min_reg_num; frame_ctx.max_reg_num = max_reg_num; frame_ctx.tmp_num_p = ecma_alloc_number (); vm_stack_add_frame (&frame_ctx.stack_frame, regs, regs_num); vm_frame_ctx_t *prev_context_p = vm_top_context_p; vm_top_context_p = &frame_ctx; #ifdef MEM_STATS interp_mem_stats_context_enter (&frame_ctx, start_pos); #endif /* MEM_STATS */ completion = vm_loop (&frame_ctx, NULL); JERRY_ASSERT (ecma_is_completion_value_throw (completion) || ecma_is_completion_value_return (completion)); vm_top_context_p = prev_context_p; vm_stack_free_frame (&frame_ctx.stack_frame); ecma_dealloc_number (frame_ctx.tmp_num_p); #ifdef MEM_STATS interp_mem_stats_context_exit (&frame_ctx, start_pos); #endif /* MEM_STATS */ MEM_FINALIZE_LOCAL_ARRAY (regs); return completion; } /* vm_run_from_pos */
/** * Run the code, starting from specified opcode */ ecma_completion_value_t vm_run_from_pos (opcode_counter_t start_pos, /**< identifier of starting opcode */ ecma_value_t this_binding_value, /**< value of 'ThisBinding' */ ecma_object_t *lex_env_p, /**< lexical environment to use */ bool is_strict, /**< is the code is strict mode code (ECMA-262 v5, 10.1.1) */ bool is_eval_code) /**< is the code is eval code (ECMA-262 v5, 10.1) */ { ecma_completion_value_t completion; const opcode_t *curr = &__program[start_pos]; JERRY_ASSERT (curr->op_idx == __op__idx_reg_var_decl); const idx_t min_reg_num = curr->data.reg_var_decl.min; const idx_t max_reg_num = curr->data.reg_var_decl.max; JERRY_ASSERT (max_reg_num >= min_reg_num); const int32_t regs_num = max_reg_num - min_reg_num + 1; MEM_DEFINE_LOCAL_ARRAY (regs, regs_num, ecma_value_t); int_data_t int_data; int_data.pos = (opcode_counter_t) (start_pos + 1); int_data.this_binding = this_binding_value; int_data.lex_env_p = lex_env_p; int_data.is_strict = is_strict; int_data.is_eval_code = is_eval_code; int_data.min_reg_num = min_reg_num; int_data.max_reg_num = max_reg_num; int_data.tmp_num_p = ecma_alloc_number (); ecma_stack_add_frame (&int_data.stack_frame, regs, regs_num); int_data_t *prev_context_p = vm_top_context_p; vm_top_context_p = &int_data; #ifdef MEM_STATS interp_mem_stats_context_enter (&int_data, start_pos); #endif /* MEM_STATS */ completion = vm_loop (&int_data, NULL); JERRY_ASSERT (ecma_is_completion_value_normal (completion) || ecma_is_completion_value_throw (completion) || ecma_is_completion_value_return (completion) || ecma_is_completion_value_exit (completion)); vm_top_context_p = prev_context_p; ecma_stack_free_frame (&int_data.stack_frame); ecma_dealloc_number (int_data.tmp_num_p); #ifdef MEM_STATS interp_mem_stats_context_exit (&int_data, start_pos); #endif /* MEM_STATS */ MEM_FINALIZE_LOCAL_ARRAY (regs); return completion; } /* vm_run_from_pos */
/** * Fill arguments' list * * @return empty completion value if argument list was filled successfully, * otherwise - not normal completion value indicating completion type * of last expression evaluated */ ecma_completion_value_t fill_varg_list (vm_frame_ctx_t *frame_ctx_p, /**< interpreter context */ ecma_length_t args_number, /**< number of arguments */ ecma_value_t arg_values[], /**< out: arguments' values */ ecma_length_t *out_arg_number_p) /**< out: number of arguments successfully read */ { ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); ecma_length_t arg_index; for (arg_index = 0; arg_index < args_number && ecma_is_completion_value_empty (ret_value); ) { ecma_completion_value_t evaluate_arg_completion = vm_loop (frame_ctx_p, NULL); if (ecma_is_completion_value_empty (evaluate_arg_completion)) { vm_instr_t next_instr = vm_get_instr (frame_ctx_p->instrs_p, frame_ctx_p->pos); JERRY_ASSERT (next_instr.op_idx == VM_OP_META); JERRY_ASSERT (next_instr.data.meta.type == OPCODE_META_TYPE_VARG); const idx_t varg_var_idx = next_instr.data.meta.data_1; ecma_completion_value_t get_arg_completion = get_variable_value (frame_ctx_p, varg_var_idx, false); if (ecma_is_completion_value_normal (get_arg_completion)) { arg_values[arg_index++] = ecma_get_completion_value_value (get_arg_completion); } else { JERRY_ASSERT (ecma_is_completion_value_throw (get_arg_completion)); ret_value = get_arg_completion; } } else { JERRY_ASSERT (ecma_is_completion_value_throw (evaluate_arg_completion)); ret_value = evaluate_arg_completion; } frame_ctx_p->pos++; } *out_arg_number_p = arg_index; return ret_value; } /* fill_varg_list */
void su_call(su_state *s, int narg, int nret) { int pc, tmp, fret; prototype_t *prot; int top = s->stack_top - narg - 1; value_t *f = &s->stack[top]; frame_t *frame = &s->frames[s->frame_top++]; assert(s->frame_top <= MAX_CALLS); frame->ret_addr = 0xffff; frame->func = f->obj.func; frame->stack_top = top; pc = s->pc; prot = s->prot; tmp = s->narg; s->narg = narg; if (f->type == SU_FUNCTION) { if (f->obj.func->narg < 0) { su_vector(s, narg); s->narg = narg = 1; } else { su_assert(s, f->obj.func->narg == narg, "Bad number of argument to function!"); } vm_loop(s, f->obj.func); if (nret == 0) su_pop(s, 1); } else if (f->type == SU_NATIVEFUNC) { fret = f->obj.nfunc(s, narg); if (nret > 0 && fret > 0) { s->stack[top] = *STK(-1); su_pop(s, narg); } else { s->stack_top = top; if (nret > 0) su_pushnil(s); } s->frame_top--; } else { assert(0); } s->narg = tmp; s->prot = prot; s->pc = pc; }
static void * start_thread(void *param) { char tname[MAXCOMLEN + 1]; struct mt_vmm_info *mtp; int vcpu; mtp = param; vcpu = mtp->mt_vcpu; snprintf(tname, sizeof(tname), "vcpu %d", vcpu); pthread_setname_np(mtp->mt_thr, tname); vm_loop(mtp->mt_ctx); /* reset or halt */ return NULL; }
static void * fbsdrun_start_thread(void *param) { char tname[MAXCOMLEN + 1]; struct mt_vmm_info *mtp; int vcpu; mtp = param; vcpu = mtp->mt_vcpu; snprintf(tname, sizeof(tname), "vcpu %d", vcpu); pthread_set_name_np(mtp->mt_thr, tname); vm_loop(mtp->mt_ctx, vcpu, vmexit[vcpu].rip); /* not reached */ exit(1); return (NULL); }
/** * 'Try' opcode handler. * * See also: ECMA-262 v5, 12.14 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t opfunc_try_block (opcode_t opdata, /**< operation data */ vm_frame_ctx_t *frame_ctx_p) /**< interpreter context */ { const idx_t block_end_oc_idx_1 = opdata.data.try_block.oc_idx_1; const idx_t block_end_oc_idx_2 = opdata.data.try_block.oc_idx_2; const opcode_counter_t try_end_oc = (opcode_counter_t) ( calc_opcode_counter_from_idx_idx (block_end_oc_idx_1, block_end_oc_idx_2) + frame_ctx_p->pos); frame_ctx_p->pos++; vm_run_scope_t run_scope_try = { frame_ctx_p->pos, try_end_oc }; ecma_completion_value_t try_completion = vm_loop (frame_ctx_p, &run_scope_try); JERRY_ASSERT ((!ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos <= try_end_oc) || (ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos == try_end_oc)); frame_ctx_p->pos = try_end_oc; opcode_t next_opcode = vm_get_opcode (frame_ctx_p->opcodes_p, frame_ctx_p->pos); JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); if (next_opcode.data.meta.type == OPCODE_META_TYPE_CATCH) { const opcode_counter_t catch_end_oc = (opcode_counter_t) ( read_meta_opcode_counter (OPCODE_META_TYPE_CATCH, frame_ctx_p) + frame_ctx_p->pos); frame_ctx_p->pos++; if (ecma_is_completion_value_throw (try_completion)) { next_opcode = vm_get_opcode (frame_ctx_p->opcodes_p, frame_ctx_p->pos); JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); JERRY_ASSERT (next_opcode.data.meta.type == OPCODE_META_TYPE_CATCH_EXCEPTION_IDENTIFIER); lit_cpointer_t catch_exc_val_var_name_lit_cp = serializer_get_literal_cp_by_uid (next_opcode.data.meta.data_1, frame_ctx_p->opcodes_p, frame_ctx_p->pos); frame_ctx_p->pos++; ecma_string_t *catch_exc_var_name_str_p = ecma_new_ecma_string_from_lit_cp (catch_exc_val_var_name_lit_cp); ecma_object_t *old_env_p = frame_ctx_p->lex_env_p; ecma_object_t *catch_env_p = ecma_create_decl_lex_env (old_env_p); ecma_completion_value_t completion = ecma_op_create_mutable_binding (catch_env_p, catch_exc_var_name_str_p, false); JERRY_ASSERT (ecma_is_completion_value_empty (completion)); completion = ecma_op_set_mutable_binding (catch_env_p, catch_exc_var_name_str_p, ecma_get_completion_value_value (try_completion), false); JERRY_ASSERT (ecma_is_completion_value_empty (completion)); ecma_deref_ecma_string (catch_exc_var_name_str_p); frame_ctx_p->lex_env_p = catch_env_p; ecma_free_completion_value (try_completion); vm_run_scope_t run_scope_catch = { frame_ctx_p->pos, catch_end_oc }; try_completion = vm_loop (frame_ctx_p, &run_scope_catch); frame_ctx_p->lex_env_p = old_env_p; ecma_deref_object (catch_env_p); JERRY_ASSERT ((!ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos <= catch_end_oc) || (ecma_is_completion_value_empty (try_completion) && frame_ctx_p->pos == catch_end_oc)); } frame_ctx_p->pos = catch_end_oc; } next_opcode = vm_get_opcode (frame_ctx_p->opcodes_p, frame_ctx_p->pos); JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); if (next_opcode.data.meta.type == OPCODE_META_TYPE_FINALLY) { const opcode_counter_t finally_end_oc = (opcode_counter_t) ( read_meta_opcode_counter (OPCODE_META_TYPE_FINALLY, frame_ctx_p) + frame_ctx_p->pos); frame_ctx_p->pos++; vm_run_scope_t run_scope_finally = { frame_ctx_p->pos, finally_end_oc }; ecma_completion_value_t finally_completion = vm_loop (frame_ctx_p, &run_scope_finally); JERRY_ASSERT ((!ecma_is_completion_value_empty (finally_completion) && frame_ctx_p->pos <= finally_end_oc) || (ecma_is_completion_value_empty (finally_completion) && frame_ctx_p->pos == finally_end_oc)); frame_ctx_p->pos = finally_end_oc; if (!ecma_is_completion_value_empty (finally_completion)) { ecma_free_completion_value (try_completion); try_completion = finally_completion; } } next_opcode = vm_get_opcode (frame_ctx_p->opcodes_p, frame_ctx_p->pos++); JERRY_ASSERT (next_opcode.op_idx == __op__idx_meta); JERRY_ASSERT (next_opcode.data.meta.type == OPCODE_META_TYPE_END_TRY_CATCH_FINALLY); return try_completion; } /* opfunc_try_block */
/** * 'for-in' opcode handler * * See also: * ECMA-262 v5, 12.6.4 * * @return completion value * Returned value must be freed with ecma_free_completion_value */ ecma_completion_value_t opfunc_for_in (vm_instr_t instr, /**< instruction */ vm_frame_ctx_t *int_data_p) /**< interpreter context */ { const idx_t expr_idx = instr.data.for_in.expr; const idx_t block_end_oc_idx_1 = instr.data.for_in.oc_idx_1; const idx_t block_end_oc_idx_2 = instr.data.for_in.oc_idx_2; const vm_instr_counter_t for_in_end_oc = (vm_instr_counter_t) ( vm_calc_instr_counter_from_idx_idx (block_end_oc_idx_1, block_end_oc_idx_2) + int_data_p->pos); ecma_completion_value_t ret_value = ecma_make_empty_completion_value (); /* 1., 2. */ ECMA_TRY_CATCH (expr_value, get_variable_value (int_data_p, expr_idx, false), ret_value); int_data_p->pos++; vm_instr_t meta_instr = vm_get_instr (int_data_p->instrs_p, for_in_end_oc); JERRY_ASSERT (meta_instr.op_idx == VM_OP_META); JERRY_ASSERT (meta_instr.data.meta.type == OPCODE_META_TYPE_END_FOR_IN); /* 3. */ if (!ecma_is_value_undefined (expr_value) && !ecma_is_value_null (expr_value)) { /* 4. */ ECMA_TRY_CATCH (obj_expr_value, ecma_op_to_object (expr_value), ret_value); ecma_object_t *obj_p = ecma_get_object_from_value (obj_expr_value); ecma_collection_iterator_t names_iterator; ecma_collection_header_t *names_p = vm_helper_for_in_enumerate_properties_names (obj_p); if (names_p != NULL) { ecma_collection_iterator_init (&names_iterator, names_p); const vm_instr_counter_t for_in_body_begin_oc = int_data_p->pos; const vm_instr_counter_t for_in_body_end_oc = for_in_end_oc; while (ecma_collection_iterator_next (&names_iterator)) { ecma_value_t name_value = *names_iterator.current_value_p; ecma_string_t *name_p = ecma_get_string_from_value (name_value); if (ecma_op_object_get_property (obj_p, name_p) != NULL) { ecma_completion_value_t completion = set_variable_value (int_data_p, int_data_p->pos, OPCODE_REG_SPECIAL_FOR_IN_PROPERTY_NAME, name_value); JERRY_ASSERT (ecma_is_completion_value_empty (completion)); vm_run_scope_t run_scope_for_in = { for_in_body_begin_oc, for_in_body_end_oc }; ecma_completion_value_t for_in_body_completion = vm_loop (int_data_p, &run_scope_for_in); if (ecma_is_completion_value_empty (for_in_body_completion)) { JERRY_ASSERT (int_data_p->pos == for_in_body_end_oc); int_data_p->pos = for_in_body_begin_oc; } else { JERRY_ASSERT (ecma_is_completion_value_throw (for_in_body_completion) || ecma_is_completion_value_return (for_in_body_completion) || ecma_is_completion_value_jump (for_in_body_completion)); JERRY_ASSERT (int_data_p->pos <= for_in_body_end_oc); ret_value = for_in_body_completion; break; } } } ecma_free_values_collection (names_p, true); } ECMA_FINALIZE (obj_expr_value); } int_data_p->pos = (vm_instr_counter_t) (for_in_end_oc + 1u); ECMA_FINALIZE (expr_value); return ret_value; } /* opfunc_for_in */
/** * Run the code, starting from specified instruction position */ ecma_completion_value_t vm_run_from_pos (const bytecode_data_header_t *header_p, /**< byte-code data header */ vm_instr_counter_t start_pos, /**< position of starting instruction */ ecma_value_t this_binding_value, /**< value of 'ThisBinding' */ ecma_object_t *lex_env_p, /**< lexical environment to use */ bool is_strict, /**< is the code is strict mode code (ECMA-262 v5, 10.1.1) */ bool is_eval_code, /**< is the code is eval code (ECMA-262 v5, 10.1) */ ecma_collection_header_t *arg_collection_p) /**< * - collection of function call arguments, * if arguments for the called function * are placed on registers; * - NULL - otherwise. */ { ecma_completion_value_t completion; const vm_instr_t *instrs_p = header_p->instrs_p; const vm_instr_t *curr = &instrs_p[start_pos]; JERRY_ASSERT (curr->op_idx == VM_OP_REG_VAR_DECL); const uint32_t tmp_regs_num = curr->data.reg_var_decl.tmp_regs_num; const uint32_t local_var_regs_num = curr->data.reg_var_decl.local_var_regs_num; const uint32_t arg_regs_num = curr->data.reg_var_decl.arg_regs_num; uint32_t regs_num = VM_SPECIAL_REGS_NUMBER + tmp_regs_num + local_var_regs_num + arg_regs_num; MEM_DEFINE_LOCAL_ARRAY (regs, regs_num, ecma_value_t); vm_frame_ctx_t frame_ctx; frame_ctx.bytecode_header_p = header_p; frame_ctx.pos = (vm_instr_counter_t) (start_pos + 1); frame_ctx.lex_env_p = lex_env_p; frame_ctx.is_strict = is_strict; frame_ctx.is_eval_code = is_eval_code; frame_ctx.is_call_in_direct_eval_form = false; frame_ctx.tmp_num_p = ecma_alloc_number (); vm_stack_add_frame (&frame_ctx.stack_frame, regs, regs_num, local_var_regs_num, arg_regs_num, arg_collection_p); vm_stack_frame_set_reg_value (&frame_ctx.stack_frame, VM_REG_SPECIAL_THIS_BINDING, ecma_copy_value (this_binding_value, false)); vm_frame_ctx_t *prev_context_p = vm_top_context_p; vm_top_context_p = &frame_ctx; #ifdef MEM_STATS interp_mem_stats_context_enter (&frame_ctx, start_pos); #endif /* MEM_STATS */ completion = vm_loop (&frame_ctx, NULL); JERRY_ASSERT (ecma_is_completion_value_throw (completion) || ecma_is_completion_value_return (completion)); vm_top_context_p = prev_context_p; vm_stack_free_frame (&frame_ctx.stack_frame); ecma_dealloc_number (frame_ctx.tmp_num_p); #ifdef MEM_STATS interp_mem_stats_context_exit (&frame_ctx, start_pos); #endif /* MEM_STATS */ MEM_FINALIZE_LOCAL_ARRAY (regs); return completion; } /* vm_run_from_pos */