Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
ruby/vm_exec.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
197 lines (157 sloc)
4.48 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -*-c-*- */ | |
/********************************************************************** | |
vm_exec.c - | |
$Author$ | |
Copyright (C) 2004-2007 Koichi Sasada | |
**********************************************************************/ | |
#include <math.h> | |
#if VM_COLLECT_USAGE_DETAILS | |
static void vm_analysis_insn(int insn); | |
#endif | |
MAYBE_UNUSED(static void vm_insns_counter_count_insn(int insn)); | |
#if USE_INSNS_COUNTER | |
static size_t rb_insns_counter[VM_INSTRUCTION_SIZE]; | |
static void | |
vm_insns_counter_count_insn(int insn) | |
{ | |
rb_insns_counter[insn]++; | |
} | |
__attribute__((destructor)) | |
static void | |
vm_insns_counter_show_results_at_exit(void) | |
{ | |
int insn_end = (ruby_vm_event_enabled_global_flags & ISEQ_TRACE_EVENTS) | |
? VM_INSTRUCTION_SIZE : VM_INSTRUCTION_SIZE / 2; | |
size_t total = 0; | |
for (int insn = 0; insn < insn_end; insn++) | |
total += rb_insns_counter[insn]; | |
for (int insn = 0; insn < insn_end; insn++) { | |
fprintf(stderr, "[RUBY_INSNS_COUNTER]\t%-32s%'12"PRIuSIZE" (%4.1f%%)\n", | |
insn_name(insn), rb_insns_counter[insn], | |
100.0 * rb_insns_counter[insn] / total); | |
} | |
} | |
#else | |
static void vm_insns_counter_count_insn(int insn) {} | |
#endif | |
#if VMDEBUG > 0 | |
#define DECL_SC_REG(type, r, reg) register type reg_##r | |
#elif defined(__GNUC__) && defined(__x86_64__) | |
#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg) | |
#elif defined(__GNUC__) && defined(__i386__) | |
#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("e" reg) | |
#elif defined(__GNUC__) && (defined(__powerpc64__) || defined(__POWERPC__)) | |
#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg) | |
#elif defined(__GNUC__) && defined(__aarch64__) | |
#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("x" reg) | |
#else | |
#define DECL_SC_REG(type, r, reg) register type reg_##r | |
#endif | |
/* #define DECL_SC_REG(r, reg) VALUE reg_##r */ | |
#if !OPT_CALL_THREADED_CODE | |
static VALUE | |
vm_exec_core(rb_execution_context_t *ec, VALUE initial) | |
{ | |
#if OPT_STACK_CACHING | |
#if 0 | |
#elif __GNUC__ && __x86_64__ | |
DECL_SC_REG(VALUE, a, "12"); | |
DECL_SC_REG(VALUE, b, "13"); | |
#else | |
register VALUE reg_a; | |
register VALUE reg_b; | |
#endif | |
#endif | |
#if defined(__GNUC__) && defined(__i386__) | |
DECL_SC_REG(const VALUE *, pc, "di"); | |
DECL_SC_REG(rb_control_frame_t *, cfp, "si"); | |
#define USE_MACHINE_REGS 1 | |
#elif defined(__GNUC__) && defined(__x86_64__) | |
DECL_SC_REG(const VALUE *, pc, "14"); | |
DECL_SC_REG(rb_control_frame_t *, cfp, "15"); | |
#define USE_MACHINE_REGS 1 | |
#elif defined(__GNUC__) && (defined(__powerpc64__) || defined(__POWERPC__)) | |
DECL_SC_REG(const VALUE *, pc, "14"); | |
DECL_SC_REG(rb_control_frame_t *, cfp, "15"); | |
#define USE_MACHINE_REGS 1 | |
#elif defined(__GNUC__) && defined(__aarch64__) | |
DECL_SC_REG(const VALUE *, pc, "19"); | |
DECL_SC_REG(rb_control_frame_t *, cfp, "20"); | |
#define USE_MACHINE_REGS 1 | |
#else | |
register rb_control_frame_t *reg_cfp; | |
const VALUE *reg_pc; | |
#define USE_MACHINE_REGS 0 | |
#endif | |
#if USE_MACHINE_REGS | |
#undef RESTORE_REGS | |
#define RESTORE_REGS() \ | |
{ \ | |
VM_REG_CFP = ec->cfp; \ | |
reg_pc = reg_cfp->pc; \ | |
} | |
#undef VM_REG_PC | |
#define VM_REG_PC reg_pc | |
#undef GET_PC | |
#define GET_PC() (reg_pc) | |
#undef SET_PC | |
#define SET_PC(x) (reg_cfp->pc = VM_REG_PC = (x)) | |
#endif | |
#if OPT_TOKEN_THREADED_CODE || OPT_DIRECT_THREADED_CODE | |
#include "vmtc.inc" | |
if (UNLIKELY(ec == 0)) { | |
return (VALUE)insns_address_table; | |
} | |
#endif | |
reg_cfp = ec->cfp; | |
reg_pc = reg_cfp->pc; | |
#if OPT_STACK_CACHING | |
reg_a = initial; | |
reg_b = 0; | |
#endif | |
first: | |
INSN_DISPATCH(); | |
/*****************/ | |
#include "vm.inc" | |
/*****************/ | |
END_INSNS_DISPATCH(); | |
/* unreachable */ | |
rb_bug("vm_eval: unreachable"); | |
goto first; | |
} | |
const void ** | |
rb_vm_get_insns_address_table(void) | |
{ | |
return (const void **)vm_exec_core(0, 0); | |
} | |
#else /* OPT_CALL_THREADED_CODE */ | |
#include "vm.inc" | |
#include "vmtc.inc" | |
const void ** | |
rb_vm_get_insns_address_table(void) | |
{ | |
return (const void **)insns_address_table; | |
} | |
static VALUE | |
vm_exec_core(rb_execution_context_t *ec, VALUE initial) | |
{ | |
register rb_control_frame_t *reg_cfp = ec->cfp; | |
rb_thread_t *th; | |
while (1) { | |
reg_cfp = ((rb_insn_func_t) (*GET_PC()))(ec, reg_cfp); | |
if (UNLIKELY(reg_cfp == 0)) { | |
break; | |
} | |
} | |
if (!UNDEF_P((th = rb_ec_thread_ptr(ec))->retval)) { | |
VALUE ret = th->retval; | |
th->retval = Qundef; | |
return ret; | |
} | |
else { | |
VALUE err = ec->errinfo; | |
ec->errinfo = Qnil; | |
return err; | |
} | |
} | |
#endif |