static void init_named_used(MVMThreadContext *tc, MVMArgProcContext *ctx, MVMuint16 num) { ctx->named_used_size = num; if (num > 64) ctx->named_used.byte_array = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, num); else ctx->named_used.bit_field = 0; }
/* Loads the extension op records. */ static MVMExtOpRecord * deserialize_extop_records(MVMThreadContext *tc, MVMCompUnit *cu, ReaderState *rs) { MVMExtOpRecord *extops; MVMuint32 num = rs->expected_extops; MVMuint8 *pos; MVMuint32 i; if (num == 0) return NULL; extops = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, num * sizeof(MVMExtOpRecord)); pos = rs->extop_seg; for (i = 0; i < num; i++) { MVMuint32 name_idx; MVMuint16 operand_bytes = 0; MVMuint8 *operand_descriptor = extops[i].operand_descriptor; /* Read name string index. */ ensure_can_read(tc, cu, rs, pos, 4); name_idx = read_int32(pos, 0); pos += 4; /* Lookup name string. */ if (name_idx >= cu->body.num_strings) { cleanup_all(tc, rs); MVM_exception_throw_adhoc(tc, "String heap index beyond end of string heap"); } extops[i].name = MVM_cu_string(tc, cu, name_idx); /* Read operand descriptor. */ ensure_can_read(tc, cu, rs, pos, 8); memcpy(operand_descriptor, pos, 8); pos += 8; /* Validate operand descriptor. * TODO: Unify with validation in MVM_ext_register_extop? */ { MVMuint8 j = 0; for(; j < 8; j++) { MVMuint8 flags = operand_descriptor[j]; if (!flags) break; switch (flags & MVM_operand_rw_mask) { case MVM_operand_literal: goto check_literal; case MVM_operand_read_reg: case MVM_operand_write_reg: operand_bytes += 2; goto check_reg; case MVM_operand_read_lex: case MVM_operand_write_lex: operand_bytes += 4; goto check_reg; default: goto fail; } check_literal: switch (flags & MVM_operand_type_mask) { case MVM_operand_int8: operand_bytes += 1; continue; case MVM_operand_int16: operand_bytes += 2; continue; case MVM_operand_int32: operand_bytes += 4; continue; case MVM_operand_int64: operand_bytes += 8; continue; case MVM_operand_num32: operand_bytes += 4; continue; case MVM_operand_num64: operand_bytes += 8; continue; case MVM_operand_str: operand_bytes += 2; continue; case MVM_operand_coderef: operand_bytes += 2; continue; case MVM_operand_ins: case MVM_operand_callsite: default: goto fail; } check_reg: switch (flags & MVM_operand_type_mask) { case MVM_operand_int8: case MVM_operand_int16: case MVM_operand_int32: case MVM_operand_int64: case MVM_operand_num32: case MVM_operand_num64: case MVM_operand_str: case MVM_operand_obj: case MVM_operand_type_var: case MVM_operand_uint8: case MVM_operand_uint16: case MVM_operand_uint32: case MVM_operand_uint64: continue; default: goto fail; } fail: cleanup_all(tc, rs); MVM_exception_throw_adhoc(tc, "Invalid operand descriptor"); } } extops[i].operand_bytes = operand_bytes; } return extops; }
/* Does the jump into the optimized code. */ void perform_osr(MVMThreadContext *tc, MVMSpeshCandidate *specialized) { MVMJitCode *jit_code; MVMint32 num_locals; /* Work out the OSR deopt index, to locate the entry point. */ MVMint32 osr_index = get_osr_deopt_index(tc, specialized); #if MVM_LOG_OSR fprintf(stderr, "Performing OSR of frame '%s' (cuid: %s) at index %d\n", MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid), osr_index); #endif jit_code = specialized->jitcode; num_locals = jit_code && jit_code->local_types ? jit_code->num_locals : specialized->num_locals; /* Resize work area if needed. */ if (specialized->work_size > tc->cur_frame->allocd_work) { /* Resize work area. */ MVMRegister *new_work = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, specialized->work_size); MVMRegister *new_args = new_work + num_locals; memcpy(new_work, tc->cur_frame->work, tc->cur_frame->static_info->body.num_locals * sizeof(MVMRegister)); memcpy(new_args, tc->cur_frame->args, tc->cur_frame->static_info->body.cu->body.max_callsite_size * sizeof(MVMRegister)); MVM_fixed_size_free(tc, tc->instance->fsa, tc->cur_frame->allocd_work, tc->cur_frame->work); tc->cur_frame->work = new_work; tc->cur_frame->allocd_work = specialized->work_size; tc->cur_frame->args = new_args; #if MVM_LOG_OSR fprintf(stderr, "OSR resized work area of frame '%s' (cuid: %s)\n", MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid)); #endif } else if (specialized->work_size > tc->cur_frame->static_info->body.work_size) { size_t keep_bytes = tc->cur_frame->static_info->body.num_locals * sizeof(MVMRegister); size_t to_null = specialized->work_size - keep_bytes; memset((char *)tc->cur_frame->work + keep_bytes, 0, to_null); } /* Resize environment if needed. */ if (specialized->num_lexicals > tc->cur_frame->static_info->body.num_lexicals) { MVMRegister *new_env = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, specialized->env_size); if (tc->cur_frame->allocd_env) { memcpy(new_env, tc->cur_frame->env, tc->cur_frame->static_info->body.num_lexicals * sizeof(MVMRegister)); MVM_fixed_size_free(tc, tc->instance->fsa, tc->cur_frame->allocd_env, tc->cur_frame->env); } tc->cur_frame->env = new_env; tc->cur_frame->allocd_env = specialized->env_size; #if MVM_LOG_OSR fprintf(stderr, "OSR resized environment of frame '%s' (cuid: %s)\n", MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.name), MVM_string_utf8_encode_C_string(tc, tc->cur_frame->static_info->body.cuuid)); #endif } else if (specialized->env_size > tc->cur_frame->static_info->body.env_size) { size_t keep_bytes = tc->cur_frame->static_info->body.num_lexicals * sizeof(MVMRegister); size_t to_null = specialized->env_size - keep_bytes; memset((char *)tc->cur_frame->env + keep_bytes, 0, to_null); } /* Set up frame to point to spesh candidate/slots. */ tc->cur_frame->effective_spesh_slots = specialized->spesh_slots; tc->cur_frame->spesh_cand = specialized; /* Move into the optimized (and maybe JIT-compiled) code. */ if (jit_code && jit_code->num_deopts) { MVMint32 i; *(tc->interp_bytecode_start) = jit_code->bytecode; *(tc->interp_cur_op) = jit_code->bytecode; for (i = 0; i < jit_code->num_deopts; i++) { if (jit_code->deopts[i].idx == osr_index) { tc->cur_frame->jit_entry_label = jit_code->labels[jit_code->deopts[i].label]; break; } } if (i == jit_code->num_deopts) MVM_oops(tc, "JIT: Could not find OSR label"); if (tc->instance->profiling) MVM_profiler_log_osr(tc, 1); } else { *(tc->interp_bytecode_start) = specialized->bytecode; *(tc->interp_cur_op) = specialized->bytecode + specialized->deopts[2 * osr_index + 1]; if (tc->instance->profiling) MVM_profiler_log_osr(tc, 0); } *(tc->interp_reg_base) = tc->cur_frame->work; }
/* Finalizes OSR. */ void MVM_spesh_osr_finalize(MVMThreadContext *tc) { /* Find deopt index using existing deopt table, for entering the updated * code later. */ MVMSpeshCandidate *specialized = tc->cur_frame->spesh_cand; MVMint32 osr_index = get_osr_deopt_finalize_index(tc, specialized); MVMJitCode *jc; /* Finish up the specialization. */ MVM_spesh_candidate_specialize(tc, tc->cur_frame->static_info, specialized); /* Resize work area if needed. */ if (specialized->num_locals > tc->cur_frame->static_info->body.num_locals) { /* Resize work area. */ MVMRegister *new_work = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, specialized->work_size); memcpy(new_work, tc->cur_frame->work, tc->cur_frame->static_info->body.num_locals * sizeof(MVMRegister)); MVM_fixed_size_free(tc, tc->instance->fsa, tc->cur_frame->allocd_work, tc->cur_frame->work); tc->cur_frame->work = new_work; tc->cur_frame->allocd_work = specialized->work_size; tc->cur_frame->args = tc->cur_frame->work + specialized->num_locals; } /* Resize environment if needed. */ if (specialized->num_lexicals > tc->cur_frame->static_info->body.num_lexicals) { MVMRegister *new_env = MVM_fixed_size_alloc_zeroed(tc, tc->instance->fsa, specialized->env_size); if (tc->cur_frame->allocd_env) { memcpy(new_env, tc->cur_frame->env, tc->cur_frame->static_info->body.num_lexicals * sizeof(MVMRegister)); MVM_fixed_size_free(tc, tc->instance->fsa, tc->cur_frame->allocd_env, tc->cur_frame->env); } tc->cur_frame->env = new_env; tc->cur_frame->allocd_env = specialized->env_size; } /* Sync frame with updates. */ tc->cur_frame->effective_bytecode = specialized->bytecode; tc->cur_frame->effective_handlers = specialized->handlers; tc->cur_frame->effective_spesh_slots = specialized->spesh_slots; tc->cur_frame->spesh_log_slots = NULL; tc->cur_frame->spesh_log_idx = -1; /* Sync interpreter with updates. */ jc = specialized->jitcode; if (jc && jc->num_deopts) { MVMint32 i; *(tc->interp_bytecode_start) = specialized->jitcode->bytecode; *(tc->interp_cur_op) = specialized->jitcode->bytecode; for (i = 0; i < jc->num_deopts; i++) { if (jc->deopts[i].idx == osr_index) { tc->cur_frame->jit_entry_label = jc->labels[jc->deopts[i].label]; break; } } if (i == jc->num_deopts) MVM_oops(tc, "JIT: Could not find OSR label"); if (tc->instance->profiling) MVM_profiler_log_osr(tc, 1); } else { *(tc->interp_bytecode_start) = specialized->bytecode; *(tc->interp_cur_op) = specialized->bytecode + specialized->deopts[2 * osr_index + 1]; if (tc->instance->profiling) MVM_profiler_log_osr(tc, 0); } *(tc->interp_reg_base) = tc->cur_frame->work; /* Tweak frame invocation count so future invocations will use the code * produced by OSR. */ tc->cur_frame->static_info->body.invocations += tc->cur_frame->static_info->body.spesh_threshold; }