* *.def, proc.c, vm_opts.h.base, template/*: set properties.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@11617 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
6cee897b59
commit
c1f5d22719
@ -1,29 +1,29 @@
|
|||||||
#
|
#
|
||||||
# a definition of instruction unification
|
# a definition of instruction unification
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
putobject putobject
|
putobject putobject
|
||||||
putobject putstring
|
putobject putstring
|
||||||
putobject setlocal
|
putobject setlocal
|
||||||
putobject setdynamic
|
putobject setdynamic
|
||||||
|
|
||||||
putstring putstring
|
putstring putstring
|
||||||
putstring putobject
|
putstring putobject
|
||||||
putstring setlocal
|
putstring setlocal
|
||||||
putstring setdynamic
|
putstring setdynamic
|
||||||
|
|
||||||
# putnil end
|
# putnil end
|
||||||
|
|
||||||
dup setlocal
|
dup setlocal
|
||||||
|
|
||||||
# from tarai
|
# from tarai
|
||||||
getlocal getlocal
|
getlocal getlocal
|
||||||
# getlocal send
|
# getlocal send
|
||||||
|
|
||||||
# from tak, ackermann
|
# from tak, ackermann
|
||||||
getlocal putobject
|
getlocal putobject
|
||||||
|
|
||||||
|
|
||||||
|
118
opt_operand.def
118
opt_operand.def
@ -1,59 +1,59 @@
|
|||||||
#
|
#
|
||||||
# configration file for operand union optimization
|
# configration file for operand union optimization
|
||||||
#
|
#
|
||||||
# format:
|
# format:
|
||||||
# [insn name] op1, op2 ...
|
# [insn name] op1, op2 ...
|
||||||
#
|
#
|
||||||
# wildcard: *
|
# wildcard: *
|
||||||
#
|
#
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
getlocal 2
|
getlocal 2
|
||||||
getlocal 3
|
getlocal 3
|
||||||
getlocal 4
|
getlocal 4
|
||||||
|
|
||||||
setlocal 2
|
setlocal 2
|
||||||
setlocal 3
|
setlocal 3
|
||||||
setlocal 4
|
setlocal 4
|
||||||
|
|
||||||
getdynamic *, 0
|
getdynamic *, 0
|
||||||
getdynamic 1, 0
|
getdynamic 1, 0
|
||||||
getdynamic 2, 0
|
getdynamic 2, 0
|
||||||
getdynamic 3, 0
|
getdynamic 3, 0
|
||||||
getdynamic 4, 0
|
getdynamic 4, 0
|
||||||
|
|
||||||
setdynamic *, 0
|
setdynamic *, 0
|
||||||
setdynamic 1, 0
|
setdynamic 1, 0
|
||||||
setdynamic 2, 0
|
setdynamic 2, 0
|
||||||
setdynamic 3, 0
|
setdynamic 3, 0
|
||||||
setdynamic 4, 0
|
setdynamic 4, 0
|
||||||
|
|
||||||
putobject INT2FIX(0)
|
putobject INT2FIX(0)
|
||||||
putobject INT2FIX(1)
|
putobject INT2FIX(1)
|
||||||
putobject Qtrue
|
putobject Qtrue
|
||||||
putobject Qfalse
|
putobject Qfalse
|
||||||
|
|
||||||
# CALL
|
# CALL
|
||||||
send *, *, Qfalse, 0, *
|
send *, *, Qfalse, 0, *
|
||||||
send *, 0, Qfalse, 0, *
|
send *, 0, Qfalse, 0, *
|
||||||
send *, 1, Qfalse, 0, *
|
send *, 1, Qfalse, 0, *
|
||||||
send *, 2, Qfalse, 0, *
|
send *, 2, Qfalse, 0, *
|
||||||
send *, 3, Qfalse, 0, *
|
send *, 3, Qfalse, 0, *
|
||||||
|
|
||||||
# FCALL
|
# FCALL
|
||||||
send *, *, Qfalse, 0x04, *
|
send *, *, Qfalse, 0x04, *
|
||||||
send *, 0, Qfalse, 0x04, *
|
send *, 0, Qfalse, 0x04, *
|
||||||
send *, 1, Qfalse, 0x04, *
|
send *, 1, Qfalse, 0x04, *
|
||||||
send *, 2, Qfalse, 0x04, *
|
send *, 2, Qfalse, 0x04, *
|
||||||
send *, 3, Qfalse, 0x04, *
|
send *, 3, Qfalse, 0x04, *
|
||||||
|
|
||||||
# VCALL
|
# VCALL
|
||||||
send *, 0, Qfalse, 0x0c, *
|
send *, 0, Qfalse, 0x0c, *
|
||||||
|
|
||||||
|
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
/** -*-c-*-
|
/** -*-c-*-
|
||||||
This file contains YARV instructions list.
|
This file contains YARV instructions list.
|
||||||
|
|
||||||
----
|
----
|
||||||
This file is auto generated by insns2vm.rb
|
This file is auto generated by insns2vm.rb
|
||||||
DO NOT TOUCH!
|
DO NOT TOUCH!
|
||||||
|
|
||||||
If you want to fix something, you must edit 'template/insns.inc.tmpl'
|
If you want to fix something, you must edit 'template/insns.inc.tmpl'
|
||||||
or insns2vm.rb
|
or insns2vm.rb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* BIN : Basic Instruction Name */
|
/* BIN : Basic Instruction Name */
|
||||||
#define BIN(n) YARVINSN_##n
|
#define BIN(n) YARVINSN_##n
|
||||||
|
|
||||||
enum{
|
enum{
|
||||||
<%= insns %>
|
<%= insns %>
|
||||||
};
|
};
|
||||||
|
|
||||||
#define YARV_MAX_INSTRUCTION_SIZE <%= @insns.size %>
|
#define YARV_MAX_INSTRUCTION_SIZE <%= @insns.size %>
|
||||||
|
|
||||||
|
@ -1,77 +1,77 @@
|
|||||||
/** -*-c-*-
|
/** -*-c-*-
|
||||||
This file contains instruction information for yarv instruction sequence.
|
This file contains instruction information for yarv instruction sequence.
|
||||||
|
|
||||||
----
|
----
|
||||||
This file is auto generated by insns2vm.rb
|
This file is auto generated by insns2vm.rb
|
||||||
DO NOT TOUCH!
|
DO NOT TOUCH!
|
||||||
|
|
||||||
If you want to fix something, you must edit 'template/insns_info.inc.tmpl'
|
If you want to fix something, you must edit 'template/insns_info.inc.tmpl'
|
||||||
or insns2vm.rb
|
or insns2vm.rb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
<%= insn_type_chars %>
|
<%= insn_type_chars %>
|
||||||
|
|
||||||
static char *insn_name_info[] = {
|
static char *insn_name_info[] = {
|
||||||
<%= insn_names %>
|
<%= insn_names %>
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *insn_operand_info[] = {
|
static char *insn_operand_info[] = {
|
||||||
<%= operands_info %>
|
<%= operands_info %>
|
||||||
};
|
};
|
||||||
|
|
||||||
static int insn_len_info[] = {
|
static int insn_len_info[] = {
|
||||||
<%= operands_num_info %>
|
<%= operands_num_info %>
|
||||||
};
|
};
|
||||||
|
|
||||||
static int insn_stack_push_num_info[] = {
|
static int insn_stack_push_num_info[] = {
|
||||||
<%= stack_num_info %>
|
<%= stack_num_info %>
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
insn_stack_increase(int depth, int insn, VALUE *opes)
|
insn_stack_increase(int depth, int insn, VALUE *opes)
|
||||||
{
|
{
|
||||||
switch(insn){
|
switch(insn){
|
||||||
<%= stack_increase %>
|
<%= stack_increase %>
|
||||||
default:
|
default:
|
||||||
rb_bug("insn_sp_increase: unreachable");
|
rb_bug("insn_sp_increase: unreachable");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* some utilities */
|
/* some utilities */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
insn_len(int insn)
|
insn_len(int insn)
|
||||||
{
|
{
|
||||||
return insn_len_info[insn];
|
return insn_len_info[insn];
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
insn_name(int insn)
|
insn_name(int insn)
|
||||||
{
|
{
|
||||||
return insn_name_info[insn];
|
return insn_name_info[insn];
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
insn_op_types(int insn)
|
insn_op_types(int insn)
|
||||||
{
|
{
|
||||||
return insn_operand_info[insn];
|
return insn_operand_info[insn];
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
insn_op_type(int insn, int pos)
|
insn_op_type(int insn, int pos)
|
||||||
{
|
{
|
||||||
int len = insn_len(insn) - 1;
|
int len = insn_len(insn) - 1;
|
||||||
if(pos < len){
|
if(pos < len){
|
||||||
return insn_operand_info[insn][pos];
|
return insn_operand_info[insn][pos];
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
insn_ret_num(int insn)
|
insn_ret_num(int insn)
|
||||||
{
|
{
|
||||||
return insn_stack_push_num_info[insn];
|
return insn_stack_push_num_info[insn];
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,39 @@
|
|||||||
|
|
||||||
<?xml version='1.0' encoding='SHIFT_JIS'?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><!--
|
<?xml version='1.0' encoding='SHIFT_JIS'?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><!--
|
||||||
$Id: insnstbl.html,v 1.1 2004/02/05 04:09:25 ko1 Exp $
|
$Id$
|
||||||
diary index
|
diary index
|
||||||
--><html xml:lang='ja' xmlns='http://www.w3.org/1999/xhtml'>
|
--><html xml:lang='ja' xmlns='http://www.w3.org/1999/xhtml'>
|
||||||
<head>
|
<head>
|
||||||
<meta content='text/html;charset=Shift_JIS' http-equiv='Content-Type'/>
|
<meta content='text/html;charset=Shift_JIS' http-equiv='Content-Type'/>
|
||||||
<meta content='text/css' http-equiv='Content-Style-Type'/>
|
<meta content='text/css' http-equiv='Content-Style-Type'/>
|
||||||
<meta content='text/javascript' http-equiv='Content-Script-Type'/>
|
<meta content='text/javascript' http-equiv='Content-Script-Type'/>
|
||||||
|
|
||||||
<link href='./contents.css' rel='stylesheet' type='text/css'/>
|
<link href='./contents.css' rel='stylesheet' type='text/css'/>
|
||||||
|
|
||||||
<title>YARV: Yet another RubyVM / Instruction Table</title>
|
<title>YARV: Yet another RubyVM / Instruction Table</title>
|
||||||
|
|
||||||
<link href='mailto:ko1 at atdot.net' rev='made'/>
|
<link href='mailto:ko1 at atdot.net' rev='made'/>
|
||||||
<link href='../index.html' rel='index'/>
|
<link href='../index.html' rel='index'/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>YARV: Instruction Table</h1>
|
<h1>YARV: Instruction Table</h1>
|
||||||
<table border='1' cellspacing='1' align='center'>
|
<table border='1' cellspacing='1' align='center'>
|
||||||
<tr>
|
<tr>
|
||||||
<th>type</th>
|
<th>type</th>
|
||||||
<th>Index</th>
|
<th>Index</th>
|
||||||
<th>Instruction</th>
|
<th>Instruction</th>
|
||||||
<th>Operands</th>
|
<th>Operands</th>
|
||||||
<th colspan='3'>Stacks</th>
|
<th colspan='3'>Stacks</th>
|
||||||
</tr>
|
</tr>
|
||||||
<%= tbl %>
|
<%= tbl %>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<address>
|
<address>
|
||||||
SASADA Koichi / ko1 at atdot.net
|
SASADA Koichi / ko1 at atdot.net
|
||||||
</address>
|
</address>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
/** -*-c-*-
|
/** -*-c-*-
|
||||||
This file contains YARV instructions list, to define YARVCore::Instructions.
|
This file contains YARV instructions list, to define YARVCore::Instructions.
|
||||||
|
|
||||||
----
|
----
|
||||||
This file is auto generated by insns2vm.rb
|
This file is auto generated by insns2vm.rb
|
||||||
DO NOT TOUCH!
|
DO NOT TOUCH!
|
||||||
|
|
||||||
If you want to fix something, you must edit 'template/minsns.inc.tmpl'
|
If you want to fix something, you must edit 'template/minsns.inc.tmpl'
|
||||||
or insns2vm.rb
|
or insns2vm.rb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
<%= defs %>
|
<%= defs %>
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,32 +1,32 @@
|
|||||||
/* -*-c-*- *********************************************************/
|
/* -*-c-*- *********************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/**
|
/**
|
||||||
This file is for threaded code.
|
This file is for threaded code.
|
||||||
|
|
||||||
----
|
----
|
||||||
This file is auto generated by insns2vm.rb
|
This file is auto generated by insns2vm.rb
|
||||||
DO NOT TOUCH!
|
DO NOT TOUCH!
|
||||||
|
|
||||||
If you want to fix something, you must edit 'template/opt_sc.inc.tmpl'
|
If you want to fix something, you must edit 'template/opt_sc.inc.tmpl'
|
||||||
or rb/insns2vm.rb
|
or rb/insns2vm.rb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SC_STATE_SIZE 6
|
#define SC_STATE_SIZE 6
|
||||||
|
|
||||||
#define SCS_XX 1
|
#define SCS_XX 1
|
||||||
#define SCS_AX 2
|
#define SCS_AX 2
|
||||||
#define SCS_BX 3
|
#define SCS_BX 3
|
||||||
#define SCS_AB 4
|
#define SCS_AB 4
|
||||||
#define SCS_BA 5
|
#define SCS_BA 5
|
||||||
|
|
||||||
#define SC_ERROR 0xffffffff
|
#define SC_ERROR 0xffffffff
|
||||||
|
|
||||||
static VALUE sc_insn_info[][SC_STATE_SIZE] = {
|
static VALUE sc_insn_info[][SC_STATE_SIZE] = {
|
||||||
<%= sc_insn_info %>
|
<%= sc_insn_info %>
|
||||||
};
|
};
|
||||||
|
|
||||||
static VALUE sc_insn_next[] = {
|
static VALUE sc_insn_next[] = {
|
||||||
<%= sc_insn_next %>
|
<%= sc_insn_next %>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
/* -*-c-*- *********************************************************/
|
/* -*-c-*- *********************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/**
|
/**
|
||||||
This file is for threaded code.
|
This file is for threaded code.
|
||||||
|
|
||||||
----
|
----
|
||||||
This file is auto generated by insns2vm.rb
|
This file is auto generated by insns2vm.rb
|
||||||
DO NOT TOUCH!
|
DO NOT TOUCH!
|
||||||
|
|
||||||
If you want to fix something, you must edit 'template/optinsn.inc.tmpl'
|
If you want to fix something, you must edit 'template/optinsn.inc.tmpl'
|
||||||
or rb/insns2vm.rb
|
or rb/insns2vm.rb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static INSN *
|
static INSN *
|
||||||
insn_operands_unification(INSN *insnobj){
|
insn_operands_unification(INSN *insnobj){
|
||||||
#ifdef OPT_OPERANDS_UNIFICATION
|
#ifdef OPT_OPERANDS_UNIFICATION
|
||||||
/* optimize rule */
|
/* optimize rule */
|
||||||
switch(insnobj->insn_id){
|
switch(insnobj->insn_id){
|
||||||
|
|
||||||
<%= rule %>
|
<%= rule %>
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* do nothing */;
|
/* do nothing */;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return insnobj;
|
return insnobj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,35 +1,35 @@
|
|||||||
/* -*-c-*- *********************************************************/
|
/* -*-c-*- *********************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/**
|
/**
|
||||||
This file is for threaded code.
|
This file is for threaded code.
|
||||||
|
|
||||||
----
|
----
|
||||||
This file is auto generated by insns2vm.rb
|
This file is auto generated by insns2vm.rb
|
||||||
DO NOT TOUCH!
|
DO NOT TOUCH!
|
||||||
|
|
||||||
If you want to fix something, you must edit 'template/optunifs.inc.tmpl'
|
If you want to fix something, you must edit 'template/optunifs.inc.tmpl'
|
||||||
or rb/insns2vm.rb
|
or rb/insns2vm.rb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static int UNIFIED_insn_name_1[] = {id, size, ...};
|
static int UNIFIED_insn_name_1[] = {id, size, ...};
|
||||||
static int UNIFIED_insn_name_2[] = {id, size, ...};
|
static int UNIFIED_insn_name_2[] = {id, size, ...};
|
||||||
...
|
...
|
||||||
|
|
||||||
static *int UNIFIED_insn_name[] = {size,
|
static *int UNIFIED_insn_name[] = {size,
|
||||||
UNIFIED_insn_name_1,
|
UNIFIED_insn_name_1,
|
||||||
UNIFIED_insn_name_2, ...};
|
UNIFIED_insn_name_2, ...};
|
||||||
...
|
...
|
||||||
|
|
||||||
static **int unified_insns_data[] = {
|
static **int unified_insns_data[] = {
|
||||||
UNIFIED_insn_nameA,
|
UNIFIED_insn_nameA,
|
||||||
UNIFIED_insn_nameB, ...};
|
UNIFIED_insn_nameB, ...};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
<%= unif_insns_each %>
|
<%= unif_insns_each %>
|
||||||
<%= unif_insns %>
|
<%= unif_insns %>
|
||||||
<%= unif_insns_data %>
|
<%= unif_insns_data %>
|
||||||
|
|
||||||
#undef GET_INSN_NAME
|
#undef GET_INSN_NAME
|
||||||
|
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
/* -*-c-*- *********************************************************/
|
/* -*-c-*- *********************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/**
|
/**
|
||||||
This file is VM main loop.
|
This file is VM main loop.
|
||||||
|
|
||||||
----
|
----
|
||||||
This file is auto generated by insns2vm.rb
|
This file is auto generated by insns2vm.rb
|
||||||
DO NOT TOUCH!
|
DO NOT TOUCH!
|
||||||
|
|
||||||
If you want to fix something, you must edit 'insns.c'
|
If you want to fix something, you must edit 'insns.c'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
<%=
|
<%=
|
||||||
ret = ''
|
ret = ''
|
||||||
offset = 15
|
offset = 15
|
||||||
line_no = 0
|
line_no = 0
|
||||||
vm_body.each_line{|line|
|
vm_body.each_line{|line|
|
||||||
if line =~ /^\#line __CURRENT_LINE__/
|
if line =~ /^\#line __CURRENT_LINE__/
|
||||||
ret << line.sub(/__CURRENT_LINE__/, "#{line_no+offset}")
|
ret << line.sub(/__CURRENT_LINE__/, "#{line_no+offset}")
|
||||||
else
|
else
|
||||||
ret <<line
|
ret <<line
|
||||||
end
|
end
|
||||||
line_no += 1
|
line_no += 1
|
||||||
}
|
}
|
||||||
ret
|
ret
|
||||||
%>
|
%>
|
||||||
|
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
/* -*-c-*- *********************************************************/
|
/* -*-c-*- *********************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/*******************************************************************/
|
/*******************************************************************/
|
||||||
/**
|
/**
|
||||||
This file is for threaded code.
|
This file is for threaded code.
|
||||||
|
|
||||||
----
|
----
|
||||||
This file is auto generated by insns2vm.rb
|
This file is auto generated by insns2vm.rb
|
||||||
DO NOT TOUCH!
|
DO NOT TOUCH!
|
||||||
|
|
||||||
If you want to fix something, you must edit 'template/vmtc.inc.tmpl'
|
If you want to fix something, you must edit 'template/vmtc.inc.tmpl'
|
||||||
or insns2vm.rb
|
or insns2vm.rb
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const void *insns_address_table[] = {
|
static const void *insns_address_table[] = {
|
||||||
<%= insns_table %>
|
<%= insns_table %>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#title YARV: Yet another RubyVM - Software Architecture
|
#title YARV: Yet another RubyVM - Software Architecture
|
||||||
|
|
||||||
maybe writing.
|
maybe writing.
|
||||||
|
|
||||||
* YARV instruction set
|
* YARV instruction set
|
||||||
|
|
||||||
<%= d %>
|
<%= d %>
|
||||||
|
@ -1,454 +1,454 @@
|
|||||||
#title YARVアーキテクチャ
|
#title YARVアーキテクチャ
|
||||||
#set author 日本 Ruby の会 ささだこういち
|
#set author 日本 Ruby の会 ささだこういち
|
||||||
|
|
||||||
|
|
||||||
- 2005-03-03(Thu) 00:31:12 +0900 いろいろと書き直し
|
- 2005-03-03(Thu) 00:31:12 +0900 いろいろと書き直し
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
* これは?
|
* これは?
|
||||||
|
|
||||||
[[YARV: Yet Another RubyVM|http://www.atdot.net/yarv]] の 設計メモです。
|
[[YARV: Yet Another RubyVM|http://www.atdot.net/yarv]] の 設計メモです。
|
||||||
|
|
||||||
|
|
||||||
YARV は、Ruby プログラムのための次の機能を提供します。
|
YARV は、Ruby プログラムのための次の機能を提供します。
|
||||||
|
|
||||||
- Compiler
|
- Compiler
|
||||||
- VM Generator
|
- VM Generator
|
||||||
- VM (Virtual Machine)
|
- VM (Virtual Machine)
|
||||||
- Assembler
|
- Assembler
|
||||||
- Dis-Assembler
|
- Dis-Assembler
|
||||||
- (experimental) JIT Compiler
|
- (experimental) JIT Compiler
|
||||||
- (experimental) AOT Compiler
|
- (experimental) AOT Compiler
|
||||||
|
|
||||||
|
|
||||||
現在の YARV は Ruby インタプリタの拡張ライブラリとして実装しています。こ
|
現在の YARV は Ruby インタプリタの拡張ライブラリとして実装しています。こ
|
||||||
れにより、Ruby インタプリタの必要な機能(パーサ、オブジェクト管理、既存
|
れにより、Ruby インタプリタの必要な機能(パーサ、オブジェクト管理、既存
|
||||||
の拡張ライブラリ)などがほぼそのまま利用できます。
|
の拡張ライブラリ)などがほぼそのまま利用できます。
|
||||||
|
|
||||||
ただし、いくつかのパッチを Ruby インタプリタに当てなければなりません。
|
ただし、いくつかのパッチを Ruby インタプリタに当てなければなりません。
|
||||||
|
|
||||||
今後は、Ruby 本体のインタプリタ部分(eval.c)を置き換えることを目指して
|
今後は、Ruby 本体のインタプリタ部分(eval.c)を置き換えることを目指して
|
||||||
開発を継続する予定です。
|
開発を継続する予定です。
|
||||||
|
|
||||||
|
|
||||||
* Compiler (compile.h, compile.c)
|
* Compiler (compile.h, compile.c)
|
||||||
|
|
||||||
コンパイラは、Ruby インタプリタのパーサによって生成された構文木(RNode
|
コンパイラは、Ruby インタプリタのパーサによって生成された構文木(RNode
|
||||||
データによる木)を YARV 命令列に変換します。YARV 命令については後述しま
|
データによる木)を YARV 命令列に変換します。YARV 命令については後述しま
|
||||||
す。
|
す。
|
||||||
|
|
||||||
とくに難しいことはしていませんが、スコープなどの開始時にローカル変数の初
|
とくに難しいことはしていませんが、スコープなどの開始時にローカル変数の初
|
||||||
期化などを行い、あとは構文木を辿り変換していきます。
|
期化などを行い、あとは構文木を辿り変換していきます。
|
||||||
|
|
||||||
変換中は Ruby の Array オブジェクトに YARV 命令オブジェクト、およびオペ
|
変換中は Ruby の Array オブジェクトに YARV 命令オブジェクト、およびオペ
|
||||||
ランドを格納していき、最後に実行できる形に変換します。コンパイラでは、コ
|
ランドを格納していき、最後に実行できる形に変換します。コンパイラでは、コ
|
||||||
ンパイル中に生成するメモリ領域の管理が問題になることがありますが、YARV
|
ンパイル中に生成するメモリ領域の管理が問題になることがありますが、YARV
|
||||||
の場合、Ruby インタプリタがすべて面倒をみてくれるのでこの部分は非常に楽
|
の場合、Ruby インタプリタがすべて面倒をみてくれるのでこの部分は非常に楽
|
||||||
に作ることができました(ガーベージコレクタによって自動的にメモリ管理をし
|
に作ることができました(ガーベージコレクタによって自動的にメモリ管理をし
|
||||||
てくれるため)。
|
てくれるため)。
|
||||||
|
|
||||||
YARV 命令は、命令を示す識別子、オペランドなど、すべて 1 word (マシンで
|
YARV 命令は、命令を示す識別子、オペランドなど、すべて 1 word (マシンで
|
||||||
表現できる自然な値。C 言語ではポインタのサイズ。Ruby インタプリタ用語で
|
表現できる自然な値。C 言語ではポインタのサイズ。Ruby インタプリタ用語で
|
||||||
は VALUE のサイズ)で表現されます。そのため、YARV 命令はいわゆる「バイト
|
は VALUE のサイズ)で表現されます。そのため、YARV 命令はいわゆる「バイト
|
||||||
コード」ではありません。そのため、YARV の説明などでは「命令列」という用
|
コード」ではありません。そのため、YARV の説明などでは「命令列」という用
|
||||||
語を使っています。
|
語を使っています。
|
||||||
|
|
||||||
1 word であるため、メモリの利用効率は多少悪くなりますが、アクセス速度な
|
1 word であるため、メモリの利用効率は多少悪くなりますが、アクセス速度な
|
||||||
どを考慮すると、本方式が一番いいと考えております。たとえばオペランドをコ
|
どを考慮すると、本方式が一番いいと考えております。たとえばオペランドをコ
|
||||||
ンスタントプールに格納し、インデックスのみをオペランドで示すことも可能で
|
ンスタントプールに格納し、インデックスのみをオペランドで示すことも可能で
|
||||||
すが、間接アクセスになってしまうので性能に影響が出るため、却下しました。
|
すが、間接アクセスになってしまうので性能に影響が出るため、却下しました。
|
||||||
|
|
||||||
|
|
||||||
* VM Generator (rb/insns2vm.rb, insns.def)
|
* VM Generator (rb/insns2vm.rb, insns.def)
|
||||||
|
|
||||||
rb/insns2vm.rb というスクリプトは、insns.def というファイルを読み込み、
|
rb/insns2vm.rb というスクリプトは、insns.def というファイルを読み込み、
|
||||||
VM のために必要なファイルを生成します。具体的には、命令を実行する部分を
|
VM のために必要なファイルを生成します。具体的には、命令を実行する部分を
|
||||||
生成しますが、ほかにもコンパイルに必要な情報、最適化に必要な情報、やアセ
|
生成しますが、ほかにもコンパイルに必要な情報、最適化に必要な情報、やアセ
|
||||||
ンブラ、逆アセンブラに必要な情報を示すファイルも生成します。
|
ンブラ、逆アセンブラに必要な情報を示すファイルも生成します。
|
||||||
|
|
||||||
|
|
||||||
** 命令記述
|
** 命令記述
|
||||||
|
|
||||||
insns.def には、各命令がどのような命令であるかを記述します。具体的には次
|
insns.def には、各命令がどのような命令であるかを記述します。具体的には次
|
||||||
の情報を記述します。
|
の情報を記述します。
|
||||||
|
|
||||||
- 命令の名前
|
- 命令の名前
|
||||||
- その命令のカテゴリ、コメント(英語、日本語)
|
- その命令のカテゴリ、コメント(英語、日本語)
|
||||||
- オペランドの名前
|
- オペランドの名前
|
||||||
- その命令実行前にスタックからポップする値
|
- その命令実行前にスタックからポップする値
|
||||||
- その命令実行後にスタックにプッシュする値
|
- その命令実行後にスタックにプッシュする値
|
||||||
- その命令のロジック(C 言語で記述)
|
- その命令のロジック(C 言語で記述)
|
||||||
|
|
||||||
たとえば、スタックに self をおく putself という命令は次のように記述しま
|
たとえば、スタックに self をおく putself という命令は次のように記述しま
|
||||||
す。
|
す。
|
||||||
|
|
||||||
#code
|
#code
|
||||||
/**
|
/**
|
||||||
@c put
|
@c put
|
||||||
@e put self.
|
@e put self.
|
||||||
@j self を置く。
|
@j self を置く。
|
||||||
*/
|
*/
|
||||||
DEFINE_INSN
|
DEFINE_INSN
|
||||||
putself
|
putself
|
||||||
()
|
()
|
||||||
()
|
()
|
||||||
(VALUE val)
|
(VALUE val)
|
||||||
{
|
{
|
||||||
val = GET_SELF();
|
val = GET_SELF();
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
この場合、オペランドと、スタックからポップする値は無いことになります。命
|
この場合、オペランドと、スタックからポップする値は無いことになります。命
|
||||||
令終了後、self をスタックトップに置きたいわけですが、それは val という、
|
令終了後、self をスタックトップに置きたいわけですが、それは val という、
|
||||||
スタックにプッシュする値として宣言しておいた変数に代入しておくことで、こ
|
スタックにプッシュする値として宣言しておいた変数に代入しておくことで、こ
|
||||||
れを変換するとスタックトップに置く C プログラムが生成されます。
|
れを変換するとスタックトップに置く C プログラムが生成されます。
|
||||||
|
|
||||||
細かいフォーマットは insns.def の冒頭を参照してください。そんなに難しく
|
細かいフォーマットは insns.def の冒頭を参照してください。そんなに難しく
|
||||||
ないと思います。
|
ないと思います。
|
||||||
|
|
||||||
insnhelper.h というファイルに、命令ロジックを記述するために必要なマクロ
|
insnhelper.h というファイルに、命令ロジックを記述するために必要なマクロ
|
||||||
が定義されています。また、VM の内部構造に関する定義は vm.h というファイ
|
が定義されています。また、VM の内部構造に関する定義は vm.h というファイ
|
||||||
ルにあります。
|
ルにあります。
|
||||||
|
|
||||||
|
|
||||||
* VM (Virtual Machine, vm.h, vm.c)
|
* VM (Virtual Machine, vm.h, vm.c)
|
||||||
|
|
||||||
VM は、実際にコンパイルした結果生成される YARV 命令列を実行します。まさ
|
VM は、実際にコンパイルした結果生成される YARV 命令列を実行します。まさ
|
||||||
に、この部分が YARV のキモになり、将来的には eval.c をこの VM で置き換え
|
に、この部分が YARV のキモになり、将来的には eval.c をこの VM で置き換え
|
||||||
たいと考えています。
|
たいと考えています。
|
||||||
|
|
||||||
現在の Ruby インタプリタで実行できるすべてのことが、この VM で実現できる
|
現在の Ruby インタプリタで実行できるすべてのことが、この VM で実現できる
|
||||||
ように作っています(現段階ではまだ完全ではありませんが、そうなるべきです)。
|
ように作っています(現段階ではまだ完全ではありませんが、そうなるべきです)。
|
||||||
|
|
||||||
VM は、単純なスタックマシンとして実装しています。スレッドひとつにスタッ
|
VM は、単純なスタックマシンとして実装しています。スレッドひとつにスタッ
|
||||||
クひとつを保持します。スタックの領域はヒープから取得するので、柔軟な領域
|
クひとつを保持します。スタックの領域はヒープから取得するので、柔軟な領域
|
||||||
設定が可能です。
|
設定が可能です。
|
||||||
|
|
||||||
|
|
||||||
** レジスタ
|
** レジスタ
|
||||||
|
|
||||||
VM は 5 つの仮想的なレジスタによって制御されます。
|
VM は 5 つの仮想的なレジスタによって制御されます。
|
||||||
|
|
||||||
- PC (Program Counter)
|
- PC (Program Counter)
|
||||||
- SP (Stack Pointer)
|
- SP (Stack Pointer)
|
||||||
- CFP (Control Frame Pointer)
|
- CFP (Control Frame Pointer)
|
||||||
- LFP (Local Frame Pointer)
|
- LFP (Local Frame Pointer)
|
||||||
- DFP (Dynamic Frame Pointer)
|
- DFP (Dynamic Frame Pointer)
|
||||||
|
|
||||||
PC は現在実行中の命令列の位置を示します。SP はスタックトップの位置を示し
|
PC は現在実行中の命令列の位置を示します。SP はスタックトップの位置を示し
|
||||||
ます。CFP、LFP、DFP はそれぞれフレームの情報を示します。詳細は後述します。
|
ます。CFP、LFP、DFP はそれぞれフレームの情報を示します。詳細は後述します。
|
||||||
|
|
||||||
|
|
||||||
** スタックフレーム
|
** スタックフレーム
|
||||||
|
|
||||||
obsolete (update soon)
|
obsolete (update soon)
|
||||||
|
|
||||||
|
|
||||||
** フレームデザインについての補足
|
** フレームデザインについての補足
|
||||||
|
|
||||||
Lisp の処理系などをかんがえると、わざわざブロックローカルフレームとメソ
|
Lisp の処理系などをかんがえると、わざわざブロックローカルフレームとメソ
|
||||||
ッドローカルフレームのようなものを用意するのは奇異に見えるかもしれません。
|
ッドローカルフレームのようなものを用意するのは奇異に見えるかもしれません。
|
||||||
あるフレームを、入れ子構造にして、ローカル変数のアクセスはその入れ子を外
|
あるフレームを、入れ子構造にして、ローカル変数のアクセスはその入れ子を外
|
||||||
側に辿れば必ずたどり着くことができるからです(つまり、lfp は必要ない)。
|
側に辿れば必ずたどり着くことができるからです(つまり、lfp は必要ない)。
|
||||||
|
|
||||||
しかし、Ruby ではいくつか状況が違います。まず、メソッドローカルな情報が
|
しかし、Ruby ではいくつか状況が違います。まず、メソッドローカルな情報が
|
||||||
あること、具体的にはブロックとself(callee からみると reciever)です。こ
|
あること、具体的にはブロックとself(callee からみると reciever)です。こ
|
||||||
の情報をそれぞれのフレームにもたせるのは無駄です。
|
の情報をそれぞれのフレームにもたせるのは無駄です。
|
||||||
|
|
||||||
また、Ruby2.0 からはブロックローカル変数はなくなります(ブロックローカル
|
また、Ruby2.0 からはブロックローカル変数はなくなります(ブロックローカル
|
||||||
引数は残るので、構造自体はあまり変わりません)。そのため、メソッドローカ
|
引数は残るので、構造自体はあまり変わりません)。そのため、メソッドローカ
|
||||||
ル変数へのアクセスが頻発することが予想されます。
|
ル変数へのアクセスが頻発することが予想されます。
|
||||||
|
|
||||||
このとき、メソッドローカル変数へのアクセスのたびにフレーム(スコープ)の
|
このとき、メソッドローカル変数へのアクセスのたびにフレーム(スコープ)の
|
||||||
リストをたどるのは無駄であると判断し、明示的にメソッドローカルスコープと
|
リストをたどるのは無駄であると判断し、明示的にメソッドローカルスコープと
|
||||||
ブロックフレームを分離し、ブロックフレームからはメソッドローカルフレーム
|
ブロックフレームを分離し、ブロックフレームからはメソッドローカルフレーム
|
||||||
が lfpレジスタによって容易にアクセスできるようにしました。
|
が lfpレジスタによって容易にアクセスできるようにしました。
|
||||||
|
|
||||||
|
|
||||||
** メソッド呼び出しについて
|
** メソッド呼び出しについて
|
||||||
|
|
||||||
メソッド呼び出しは、YARV 命令列で記述されたメソッドか、C で記述されたメ
|
メソッド呼び出しは、YARV 命令列で記述されたメソッドか、C で記述されたメ
|
||||||
ソッドかによってディスパッチ手法が変わります。
|
ソッドかによってディスパッチ手法が変わります。
|
||||||
|
|
||||||
YARV 命令列であった場合、上述したスタックフレームを作成して命令を継続し
|
YARV 命令列であった場合、上述したスタックフレームを作成して命令を継続し
|
||||||
ます。とくに VM の関数を再帰呼び出すすることは行ないません。
|
ます。とくに VM の関数を再帰呼び出すすることは行ないません。
|
||||||
|
|
||||||
C で記述されたメソッドだった場合、単純にその関数を呼び出します(ただし、
|
C で記述されたメソッドだった場合、単純にその関数を呼び出します(ただし、
|
||||||
バックトレースを正しく生成するためにメソッド呼び出しの情報を付加してから
|
バックトレースを正しく生成するためにメソッド呼び出しの情報を付加してから
|
||||||
行ないます)。
|
行ないます)。
|
||||||
|
|
||||||
このため、VM 用スタックを別途用意したものの、プログラムによってはマシン
|
このため、VM 用スタックを別途用意したものの、プログラムによってはマシン
|
||||||
スタックを使い切ってしまう可能性があります(C -> Ruby -> C -> ... という
|
スタックを使い切ってしまう可能性があります(C -> Ruby -> C -> ... という
|
||||||
呼び出しが続いた場合)。これは、現在では避けられない仕様となっています。
|
呼び出しが続いた場合)。これは、現在では避けられない仕様となっています。
|
||||||
|
|
||||||
|
|
||||||
** 例外
|
** 例外
|
||||||
|
|
||||||
例外は、Java の JVM と同様に例外テーブルを用意することで実現します。例外
|
例外は、Java の JVM と同様に例外テーブルを用意することで実現します。例外
|
||||||
が発生したら、当該フレームを、例外テーブルを検査します。そこで、例外が発
|
が発生したら、当該フレームを、例外テーブルを検査します。そこで、例外が発
|
||||||
生したときの PC の値に合致するエントリがあった場合、そのエントリに従って
|
生したときの PC の値に合致するエントリがあった場合、そのエントリに従って
|
||||||
動作します。もしエントリが見つからなかった場合、スタックを撒き戻してまた
|
動作します。もしエントリが見つからなかった場合、スタックを撒き戻してまた
|
||||||
同様にそのスコープの例外テーブルを検査します。
|
同様にそのスコープの例外テーブルを検査します。
|
||||||
|
|
||||||
また、break、return(ブロック中)、retry なども同様の仕組みで実現します。
|
また、break、return(ブロック中)、retry なども同様の仕組みで実現します。
|
||||||
|
|
||||||
*** 例外テーブル
|
*** 例外テーブル
|
||||||
|
|
||||||
例外テーブルエントリは具体的には次の情報が格納されています。
|
例外テーブルエントリは具体的には次の情報が格納されています。
|
||||||
|
|
||||||
- 対象とする PC の範囲
|
- 対象とする PC の範囲
|
||||||
- 対象とする例外の種類
|
- 対象とする例外の種類
|
||||||
- もし対象となったときにジャンプする先(種類による)
|
- もし対象となったときにジャンプする先(種類による)
|
||||||
- もし対象となったときに起動するブロックの iseq
|
- もし対象となったときに起動するブロックの iseq
|
||||||
|
|
||||||
|
|
||||||
*** rescue
|
*** rescue
|
||||||
|
|
||||||
rescue 節はブロックとして実現しています。$! の値を唯一の引数として持ちま
|
rescue 節はブロックとして実現しています。$! の値を唯一の引数として持ちま
|
||||||
す。
|
す。
|
||||||
|
|
||||||
#code
|
#code
|
||||||
begin
|
begin
|
||||||
rescue A
|
rescue A
|
||||||
rescue B
|
rescue B
|
||||||
rescue C
|
rescue C
|
||||||
end
|
end
|
||||||
#end
|
#end
|
||||||
|
|
||||||
は、次のような Ruby スクリプトに変換されます。
|
は、次のような Ruby スクリプトに変換されます。
|
||||||
|
|
||||||
#code
|
#code
|
||||||
{|err|
|
{|err|
|
||||||
case err
|
case err
|
||||||
when A === err
|
when A === err
|
||||||
when B === err
|
when B === err
|
||||||
when C === err
|
when C === err
|
||||||
else
|
else
|
||||||
raise # yarv の命令では throw
|
raise # yarv の命令では throw
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
|
||||||
*** ensure
|
*** ensure
|
||||||
|
|
||||||
正常系(例外が発生しなかった場合)と異常系(例外が発生したときなど)の2
|
正常系(例外が発生しなかった場合)と異常系(例外が発生したときなど)の2
|
||||||
種類の命令列が生成されます。正常系では、ただの連続したコード領域としてコ
|
種類の命令列が生成されます。正常系では、ただの連続したコード領域としてコ
|
||||||
ンパイルされます。また、異常系ではブロックとして実装します。最後は必ず
|
ンパイルされます。また、異常系ではブロックとして実装します。最後は必ず
|
||||||
throw 命令で締めることになります。
|
throw 命令で締めることになります。
|
||||||
|
|
||||||
|
|
||||||
*** break, return(ブロック中)、retry
|
*** break, return(ブロック中)、retry
|
||||||
|
|
||||||
break 文、ブロック中の return 文、retry 文は throw 命令としてコンパイル
|
break 文、ブロック中の return 文、retry 文は throw 命令としてコンパイル
|
||||||
されます。どこまで戻るかは、break をフックする例外テーブルのエントリが判
|
されます。どこまで戻るかは、break をフックする例外テーブルのエントリが判
|
||||||
断します。
|
断します。
|
||||||
|
|
||||||
|
|
||||||
** 定数の検索
|
** 定数の検索
|
||||||
|
|
||||||
定数という名前なのに、Ruby ではコンパイル時に決定しません。というか、い
|
定数という名前なのに、Ruby ではコンパイル時に決定しません。というか、い
|
||||||
つまでも再定義可能になっています。
|
つまでも再定義可能になっています。
|
||||||
|
|
||||||
定数アクセスのためのRuby記述は次のようになります。
|
定数アクセスのためのRuby記述は次のようになります。
|
||||||
|
|
||||||
#code
|
#code
|
||||||
Ruby表現:
|
Ruby表現:
|
||||||
expr::ID::...::ID
|
expr::ID::...::ID
|
||||||
#end
|
#end
|
||||||
|
|
||||||
これは、yarv命令セットでは次のようになります。
|
これは、yarv命令セットでは次のようになります。
|
||||||
|
|
||||||
#code
|
#code
|
||||||
(expr)
|
(expr)
|
||||||
getconstant ID
|
getconstant ID
|
||||||
...
|
...
|
||||||
getconstant ID
|
getconstant ID
|
||||||
#end
|
#end
|
||||||
|
|
||||||
|
|
||||||
*** 定数検索パス
|
*** 定数検索パス
|
||||||
|
|
||||||
もし expr が nil だった場合、定数検索パスに従って定数を検索します。この
|
もし expr が nil だった場合、定数検索パスに従って定数を検索します。この
|
||||||
挙動は今後 Ruby 2.0 に向けて変更される場合があります。
|
挙動は今後 Ruby 2.0 に向けて変更される場合があります。
|
||||||
|
|
||||||
+ クラス、モジュールの動的ネスト関係(プログラムの字面上)をルートまで辿る
|
+ クラス、モジュールの動的ネスト関係(プログラムの字面上)をルートまで辿る
|
||||||
+ 継承関係をルート(Object)まで辿る
|
+ 継承関係をルート(Object)まで辿る
|
||||||
|
|
||||||
このため、クラス、モジュールの動的ネスト関係を保存しなければなりません。
|
このため、クラス、モジュールの動的ネスト関係を保存しなければなりません。
|
||||||
このために、thread_object には klass_nest_stack というものを用意しました。
|
このために、thread_object には klass_nest_stack というものを用意しました。
|
||||||
これは、現在のネストの情報を保存します。
|
これは、現在のネストの情報を保存します。
|
||||||
|
|
||||||
メソッド定義時、その現在のネスト情報をメソッド定義時に(dupして)加える
|
メソッド定義時、その現在のネスト情報をメソッド定義時に(dupして)加える
|
||||||
ことで、そのメソッドの実行時、そのネスト情報を参照することが可能になりま
|
ことで、そのメソッドの実行時、そのネスト情報を参照することが可能になりま
|
||||||
す。
|
す。
|
||||||
|
|
||||||
トップレベルでは、その情報はないことになります。
|
トップレベルでは、その情報はないことになります。
|
||||||
|
|
||||||
クラス/モジュール定義文実行時は、現在の情報そのものを参照することになり
|
クラス/モジュール定義文実行時は、現在の情報そのものを参照することになり
|
||||||
ます。これは、クラススコープ突入時、その情報をクラス定義文にコピーします
|
ます。これは、クラススコープ突入時、その情報をクラス定義文にコピーします
|
||||||
(すでにコピーされていれば、これを行いません)。
|
(すでにコピーされていれば、これを行いません)。
|
||||||
|
|
||||||
これにより、動的なネスト情報を統一的に扱うことができます。
|
これにより、動的なネスト情報を統一的に扱うことができます。
|
||||||
|
|
||||||
|
|
||||||
** 最適化手法
|
** 最適化手法
|
||||||
|
|
||||||
YARV では高速化を目的としているので、さまざまな最適化手法を利用していま
|
YARV では高速化を目的としているので、さまざまな最適化手法を利用していま
|
||||||
す。詳細は割愛しますが、以下に述べる最適化などを行なっております。
|
す。詳細は割愛しますが、以下に述べる最適化などを行なっております。
|
||||||
|
|
||||||
|
|
||||||
*** threaded code
|
*** threaded code
|
||||||
|
|
||||||
GCC の C 言語拡張である値としてのラベルを利用して direct threaded code
|
GCC の C 言語拡張である値としてのラベルを利用して direct threaded code
|
||||||
を実現しています。
|
を実現しています。
|
||||||
|
|
||||||
|
|
||||||
*** Peephole optimization
|
*** Peephole optimization
|
||||||
|
|
||||||
いくつかの簡単な最適化をしています。
|
いくつかの簡単な最適化をしています。
|
||||||
|
|
||||||
|
|
||||||
*** inline method cache
|
*** inline method cache
|
||||||
|
|
||||||
命令列の中にメソッド検索結果を埋め込みます。
|
命令列の中にメソッド検索結果を埋め込みます。
|
||||||
|
|
||||||
|
|
||||||
*** inline constant cache
|
*** inline constant cache
|
||||||
|
|
||||||
命令列の中に定数検索結果を埋め込みます。
|
命令列の中に定数検索結果を埋め込みます。
|
||||||
|
|
||||||
|
|
||||||
*** ブロックと Proc オブジェクトの分離
|
*** ブロックと Proc オブジェクトの分離
|
||||||
|
|
||||||
ブロック付きメソッド呼び出しが行なわれたときにはすぐにはブロックを Proc
|
ブロック付きメソッド呼び出しが行なわれたときにはすぐにはブロックを Proc
|
||||||
オブジェクトとして生成しません。これにより、必要ない Proc オブジェクトの
|
オブジェクトとして生成しません。これにより、必要ない Proc オブジェクトの
|
||||||
生成を抑えています。
|
生成を抑えています。
|
||||||
|
|
||||||
Proc メソッドは、実際に必要になった時点で作られ、そのときに環境(スコー
|
Proc メソッドは、実際に必要になった時点で作られ、そのときに環境(スコー
|
||||||
プ上に確保された変数など)をヒープに保存します。
|
プ上に確保された変数など)をヒープに保存します。
|
||||||
|
|
||||||
|
|
||||||
*** 特化命令
|
*** 特化命令
|
||||||
|
|
||||||
Fixnum 同士の加算などを正直に関数呼び出しによって行なうと、コストがかか
|
Fixnum 同士の加算などを正直に関数呼び出しによって行なうと、コストがかか
|
||||||
るので、これらのプリミティブな操作を行なうためのメソッド呼び出しは専用命
|
るので、これらのプリミティブな操作を行なうためのメソッド呼び出しは専用命
|
||||||
令を用意しました。
|
令を用意しました。
|
||||||
|
|
||||||
|
|
||||||
*** 命令融合
|
*** 命令融合
|
||||||
|
|
||||||
複数の命令を 1 命令に変換します。融合命令は opt_insn_unif.def の記述によ
|
複数の命令を 1 命令に変換します。融合命令は opt_insn_unif.def の記述によ
|
||||||
り自動的に生成されます。
|
り自動的に生成されます。
|
||||||
|
|
||||||
|
|
||||||
*** オペランド融合
|
*** オペランド融合
|
||||||
|
|
||||||
複数のオペランドを含めた命令を生成します。融合命令は opt_operand.def の
|
複数のオペランドを含めた命令を生成します。融合命令は opt_operand.def の
|
||||||
記述によって自動的に生成されます。
|
記述によって自動的に生成されます。
|
||||||
|
|
||||||
|
|
||||||
*** stack caching
|
*** stack caching
|
||||||
|
|
||||||
スタックトップを仮想レジスタに保持するようにします。現在は 2 個の仮想レ
|
スタックトップを仮想レジスタに保持するようにします。現在は 2 個の仮想レ
|
||||||
ジスタを想定し、5状態のスタックキャッシングを行ないます。スタックキャッ
|
ジスタを想定し、5状態のスタックキャッシングを行ないます。スタックキャッ
|
||||||
シングする命令は自動的に生成されます。
|
シングする命令は自動的に生成されます。
|
||||||
|
|
||||||
|
|
||||||
*** JIT Compile
|
*** JIT Compile
|
||||||
|
|
||||||
機械語を切り貼りします。非常に実験的なコードものしか作っておりません。ほ
|
機械語を切り貼りします。非常に実験的なコードものしか作っておりません。ほ
|
||||||
とんどのプログラムは動きません。
|
とんどのプログラムは動きません。
|
||||||
|
|
||||||
|
|
||||||
*** AOT Compile
|
*** AOT Compile
|
||||||
|
|
||||||
YARV 命令列を C 言語に変換します。まだ十分な最適化を行なえておりませんが、
|
YARV 命令列を C 言語に変換します。まだ十分な最適化を行なえておりませんが、
|
||||||
それなりに動きます。rb/aotc.rb がコンパイラです。
|
それなりに動きます。rb/aotc.rb がコンパイラです。
|
||||||
|
|
||||||
|
|
||||||
* Assembler (rb/yasm.rb)
|
* Assembler (rb/yasm.rb)
|
||||||
|
|
||||||
YARV 命令列のアセンブラを用意しました。使い方は rb/yasm.rb を参照してく
|
YARV 命令列のアセンブラを用意しました。使い方は rb/yasm.rb を参照してく
|
||||||
ださい(まだ、例示してある生成手法のすべてをサポートしているわけではあり
|
ださい(まだ、例示してある生成手法のすべてをサポートしているわけではあり
|
||||||
ません)。
|
ません)。
|
||||||
|
|
||||||
|
|
||||||
* Dis-Assembler (disasm.c)
|
* Dis-Assembler (disasm.c)
|
||||||
|
|
||||||
YARV 命令列を示すオブジェクト YARVCore::InstructionSequence には disasm
|
YARV 命令列を示すオブジェクト YARVCore::InstructionSequence には disasm
|
||||||
メソッドがあります。これは、命令列を逆アセンブルした文字列を返します。
|
メソッドがあります。これは、命令列を逆アセンブルした文字列を返します。
|
||||||
|
|
||||||
|
|
||||||
* YARV 命令セット
|
* YARV 命令セット
|
||||||
|
|
||||||
<%= d %>
|
<%= d %>
|
||||||
|
|
||||||
* その他
|
* その他
|
||||||
|
|
||||||
** テスト
|
** テスト
|
||||||
|
|
||||||
test/test_* がテストケースです。一応、ミスなく動くはずです。逆にいうと、
|
test/test_* がテストケースです。一応、ミスなく動くはずです。逆にいうと、
|
||||||
このテストに記述されている例ではきちんと動作するということです。
|
このテストに記述されている例ではきちんと動作するということです。
|
||||||
|
|
||||||
|
|
||||||
** ベンチマーク
|
** ベンチマーク
|
||||||
|
|
||||||
benchmark/bm_* にベンチマークプログラムがおいてあります。
|
benchmark/bm_* にベンチマークプログラムがおいてあります。
|
||||||
|
|
||||||
|
|
||||||
** 今後の予定
|
** 今後の予定
|
||||||
|
|
||||||
まだまだやらなければいけないこと、未実装部分がたくさんありますんでやって
|
まだまだやらなければいけないこと、未実装部分がたくさんありますんでやって
|
||||||
いかなければなりません。一番大きな目標は eval.c を置き換えることでしょう
|
いかなければなりません。一番大きな目標は eval.c を置き換えることでしょう
|
||||||
か。
|
か。
|
||||||
|
|
||||||
|
|
||||||
*** Verifier
|
*** Verifier
|
||||||
|
|
||||||
YARV 命令列は、ミスがあっても動かしてしまうため危険である可能性がありま
|
YARV 命令列は、ミスがあっても動かしてしまうため危険である可能性がありま
|
||||||
す。そのため、スタックの利用状態をきちんと事前に検証するようなベリファイ
|
す。そのため、スタックの利用状態をきちんと事前に検証するようなベリファイ
|
||||||
アを用意しなければならないと考えています。
|
アを用意しなければならないと考えています。
|
||||||
|
|
||||||
|
|
||||||
*** Compiled File の構想
|
*** Compiled File の構想
|
||||||
|
|
||||||
Ruby プログラムをこの命令セットにシリアライズしたデータ構造をファイルに
|
Ruby プログラムをこの命令セットにシリアライズしたデータ構造をファイルに
|
||||||
出力できるようにしたいと考えています。これを利用して一度コンパイルした命
|
出力できるようにしたいと考えています。これを利用して一度コンパイルした命
|
||||||
令列をファイルに保存しておけば、次回ロード時にはコンパイルの手間、コスト
|
令列をファイルに保存しておけば、次回ロード時にはコンパイルの手間、コスト
|
||||||
を省くことができます。
|
を省くことができます。
|
||||||
|
|
||||||
|
|
||||||
**** 全体構成
|
**** 全体構成
|
||||||
|
|
||||||
次のようなファイル構成を考えていますが、まだ未定です。
|
次のようなファイル構成を考えていますが、まだ未定です。
|
||||||
|
|
||||||
#code
|
#code
|
||||||
u4 : 4 byte unsigned storage
|
u4 : 4 byte unsigned storage
|
||||||
u2 : 2 byte unsigned storage
|
u2 : 2 byte unsigned storage
|
||||||
u1 : 1 byte unsigned storage
|
u1 : 1 byte unsigned storage
|
||||||
|
|
||||||
every storages are little endian :-)
|
every storages are little endian :-)
|
||||||
|
|
||||||
CompiledFile{
|
CompiledFile{
|
||||||
u4 magic;
|
u4 magic;
|
||||||
|
|
||||||
u2 major;
|
u2 major;
|
||||||
u2 minor;
|
u2 minor;
|
||||||
|
|
||||||
u4 character_code;
|
u4 character_code;
|
||||||
|
|
||||||
u4 constants_pool_count;
|
u4 constants_pool_count;
|
||||||
ConstantEntry constants_pool[constants_pool_count];
|
ConstantEntry constants_pool[constants_pool_count];
|
||||||
|
|
||||||
u4 block_count;
|
u4 block_count;
|
||||||
blockEntry blocks[block_count];
|
blockEntry blocks[block_count];
|
||||||
|
|
||||||
u4 method_count;
|
u4 method_count;
|
||||||
MethodEntry methods[method_count];
|
MethodEntry methods[method_count];
|
||||||
}
|
}
|
||||||
#end
|
#end
|
||||||
|
|
||||||
Java classfile のパクリ。
|
Java classfile のパクリ。
|
||||||
|
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
# -*-ruby-*-
|
# -*-ruby-*-
|
||||||
#
|
#
|
||||||
|
|
||||||
module YARVCore
|
module YARVCore
|
||||||
class InstructionSequence
|
class InstructionSequence
|
||||||
class Instruction
|
class Instruction
|
||||||
InsnID2NO = {
|
InsnID2NO = {
|
||||||
<%= insn_id2no %>
|
<%= insn_id2no %>
|
||||||
}
|
}
|
||||||
|
|
||||||
def self.id2insn_no id
|
def self.id2insn_no id
|
||||||
if InsnID2NO.has_key? id
|
if InsnID2NO.has_key? id
|
||||||
InsnID2NO[id]
|
InsnID2NO[id]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
660
vm_macro.def
660
vm_macro.def
@ -1,330 +1,330 @@
|
|||||||
/* -*- c -*- */
|
/* -*- c -*- */
|
||||||
/* do not use C++ style comment */
|
/* do not use C++ style comment */
|
||||||
/* */
|
/* */
|
||||||
|
|
||||||
|
|
||||||
MACRO macro_eval_setup_send_arguments(num, blockptr, flag, blockiseq)
|
MACRO macro_eval_setup_send_arguments(num, blockptr, flag, blockiseq)
|
||||||
{
|
{
|
||||||
if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {
|
if (flag & VM_CALL_ARGS_BLOCKARG_BIT) {
|
||||||
yarv_proc_t *po;
|
yarv_proc_t *po;
|
||||||
VALUE proc;
|
VALUE proc;
|
||||||
|
|
||||||
proc = TOPN(0);
|
proc = TOPN(0);
|
||||||
if (proc != Qnil) {
|
if (proc != Qnil) {
|
||||||
if (!yarv_obj_is_proc(proc)) {
|
if (!yarv_obj_is_proc(proc)) {
|
||||||
proc = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
|
proc = rb_check_convert_type(proc, T_DATA, "Proc", "to_proc");
|
||||||
if (!yarv_obj_is_proc(proc)) {
|
if (!yarv_obj_is_proc(proc)) {
|
||||||
rb_raise(rb_eTypeError,
|
rb_raise(rb_eTypeError,
|
||||||
"wrong argument type %s (expected Proc)",
|
"wrong argument type %s (expected Proc)",
|
||||||
rb_obj_classname(proc));
|
rb_obj_classname(proc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GetProcPtr(proc, po);
|
GetProcPtr(proc, po);
|
||||||
blockptr = &po->block;
|
blockptr = &po->block;
|
||||||
GET_BLOCK_PTR_IN_CFP(reg_cfp)->proc = proc;
|
GET_BLOCK_PTR_IN_CFP(reg_cfp)->proc = proc;
|
||||||
}
|
}
|
||||||
INC_SP(-1);
|
INC_SP(-1);
|
||||||
}
|
}
|
||||||
else if (blockiseq) {
|
else if (blockiseq) {
|
||||||
blockptr = GET_BLOCK_PTR_IN_CFP(reg_cfp);
|
blockptr = GET_BLOCK_PTR_IN_CFP(reg_cfp);
|
||||||
blockptr->iseq = blockiseq;
|
blockptr->iseq = blockiseq;
|
||||||
blockptr->proc = 0;
|
blockptr->proc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* expand top of stack? */
|
/* expand top of stack? */
|
||||||
if (flag & VM_CALL_ARGS_SPLAT_BIT) {
|
if (flag & VM_CALL_ARGS_SPLAT_BIT) {
|
||||||
VALUE ary = TOPN(0);
|
VALUE ary = TOPN(0);
|
||||||
VALUE *ptr, *dst;
|
VALUE *ptr, *dst;
|
||||||
int i;
|
int i;
|
||||||
VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_splat");
|
VALUE tmp = rb_check_convert_type(ary, T_ARRAY, "Array", "to_splat");
|
||||||
|
|
||||||
if (NIL_P(tmp)) {
|
if (NIL_P(tmp)) {
|
||||||
tmp = rb_ary_new3(1, ary);
|
tmp = rb_ary_new3(1, ary);
|
||||||
}
|
}
|
||||||
ary = tmp;
|
ary = tmp;
|
||||||
|
|
||||||
ptr = RARRAY_PTR(ary);
|
ptr = RARRAY_PTR(ary);
|
||||||
dst = GET_SP() - 1;
|
dst = GET_SP() - 1;
|
||||||
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
for (i = 0; i < RARRAY_LEN(ary); i++) {
|
||||||
dst[i] = ptr[i];
|
dst[i] = ptr[i];
|
||||||
}
|
}
|
||||||
num += i - 1;
|
num += i - 1;
|
||||||
INC_SP(i - 1);
|
INC_SP(i - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MACRO macro_eval_invoke_cfunc(num, id, recv, klass, mn, blockptr)
|
MACRO macro_eval_invoke_cfunc(num, id, recv, klass, mn, blockptr)
|
||||||
{
|
{
|
||||||
yarv_control_frame_t *cfp =
|
yarv_control_frame_t *cfp =
|
||||||
push_frame(th, 0, FRAME_MAGIC_CFUNC,
|
push_frame(th, 0, FRAME_MAGIC_CFUNC,
|
||||||
recv, (VALUE) blockptr, 0, GET_SP(), 0, 1);
|
recv, (VALUE) blockptr, 0, GET_SP(), 0, 1);
|
||||||
cfp->callee_id = id; /* TODO */
|
cfp->callee_id = id; /* TODO */
|
||||||
cfp->method_id = id;
|
cfp->method_id = id;
|
||||||
cfp->method_klass = klass;
|
cfp->method_klass = klass;
|
||||||
|
|
||||||
reg_cfp->sp -= num + 1;
|
reg_cfp->sp -= num + 1;
|
||||||
|
|
||||||
val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1);
|
val = call_cfunc(mn->nd_cfnc, recv, mn->nd_argc, num, reg_cfp->sp + 1);
|
||||||
if (reg_cfp != th->cfp + 1) {
|
if (reg_cfp != th->cfp + 1) {
|
||||||
SDR2(reg_cfp);
|
SDR2(reg_cfp);
|
||||||
SDR2(th->cfp-5);
|
SDR2(th->cfp-5);
|
||||||
rb_bug("cfp consistency error - send");
|
rb_bug("cfp consistency error - send");
|
||||||
th->cfp = reg_cfp;
|
th->cfp = reg_cfp;
|
||||||
}
|
}
|
||||||
pop_frame(th);
|
pop_frame(th);
|
||||||
}
|
}
|
||||||
|
|
||||||
MACRO macro_eval_invoke_func(niseqval, recv, klass, blockptr, num)
|
MACRO macro_eval_invoke_func(niseqval, recv, klass, blockptr, num)
|
||||||
{
|
{
|
||||||
yarv_iseq_t *niseq;
|
yarv_iseq_t *niseq;
|
||||||
VALUE *sp = GET_SP();
|
VALUE *sp = GET_SP();
|
||||||
VALUE *rsp = sp - num - 1;
|
VALUE *rsp = sp - num - 1;
|
||||||
int opt_pc = 0, clear_local_size, i;
|
int opt_pc = 0, clear_local_size, i;
|
||||||
|
|
||||||
/* TODO: eliminate it */
|
/* TODO: eliminate it */
|
||||||
GetISeqPtr(niseqval, niseq);
|
GetISeqPtr(niseqval, niseq);
|
||||||
|
|
||||||
clear_local_size = niseq->local_size - num;
|
clear_local_size = niseq->local_size - num;
|
||||||
/* set arguments */
|
/* set arguments */
|
||||||
if (niseq->arg_simple) {
|
if (niseq->arg_simple) {
|
||||||
if (niseq->argc != num) {
|
if (niseq->argc != num) {
|
||||||
rb_raise(rb_eArgError, "wrong number of arguments (%lu for %d)",
|
rb_raise(rb_eArgError, "wrong number of arguments (%lu for %d)",
|
||||||
(unsigned long)num, niseq->argc);
|
(unsigned long)num, niseq->argc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* check optional arguments */
|
/* check optional arguments */
|
||||||
if (niseq->arg_opts) {
|
if (niseq->arg_opts) {
|
||||||
int iseq_argc = niseq->argc;
|
int iseq_argc = niseq->argc;
|
||||||
int opts = niseq->arg_opts - 1;
|
int opts = niseq->arg_opts - 1;
|
||||||
|
|
||||||
if (num < iseq_argc ||
|
if (num < iseq_argc ||
|
||||||
(niseq->arg_rest == 0 && num > iseq_argc + opts)) {
|
(niseq->arg_rest == 0 && num > iseq_argc + opts)) {
|
||||||
if (0) {
|
if (0) {
|
||||||
printf("num: %lu, iseq_argc: %d, opts: %d\n",
|
printf("num: %lu, iseq_argc: %d, opts: %d\n",
|
||||||
(unsigned long)num, iseq_argc, opts);
|
(unsigned long)num, iseq_argc, opts);
|
||||||
}
|
}
|
||||||
rb_raise(rb_eArgError,
|
rb_raise(rb_eArgError,
|
||||||
"wrong number of arguments (%lu for %d)",
|
"wrong number of arguments (%lu for %d)",
|
||||||
(unsigned long)num, iseq_argc);
|
(unsigned long)num, iseq_argc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
printf("num: %lu, opts: %d, iseq_argc: %d\n",
|
printf("num: %lu, opts: %d, iseq_argc: %d\n",
|
||||||
(unsigned long)num, opts, iseq_argc);
|
(unsigned long)num, opts, iseq_argc);
|
||||||
}
|
}
|
||||||
if (num - iseq_argc < opts) {
|
if (num - iseq_argc < opts) {
|
||||||
opt_pc = niseq->arg_opt_tbl[num - iseq_argc];
|
opt_pc = niseq->arg_opt_tbl[num - iseq_argc];
|
||||||
sp += opts - (num - iseq_argc);
|
sp += opts - (num - iseq_argc);
|
||||||
num += opts - (num - iseq_argc);
|
num += opts - (num - iseq_argc);
|
||||||
clear_local_size = niseq->local_size - (iseq_argc + opts);
|
clear_local_size = niseq->local_size - (iseq_argc + opts);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
opt_pc = niseq->arg_opt_tbl[opts];
|
opt_pc = niseq->arg_opt_tbl[opts];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* check rest */
|
/* check rest */
|
||||||
if (niseq->arg_rest == -1) {
|
if (niseq->arg_rest == -1) {
|
||||||
if (niseq->arg_opts) {
|
if (niseq->arg_opts) {
|
||||||
num = niseq->argc + niseq->arg_opts;
|
num = niseq->argc + niseq->arg_opts;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
num = niseq->argc;
|
num = niseq->argc;
|
||||||
}
|
}
|
||||||
sp = &rsp[1 + num + 1];
|
sp = &rsp[1 + num + 1];
|
||||||
}
|
}
|
||||||
else if (niseq->arg_rest != 0) {
|
else if (niseq->arg_rest != 0) {
|
||||||
int rest = niseq->arg_rest - 1;
|
int rest = niseq->arg_rest - 1;
|
||||||
int pack_size = num - rest;
|
int pack_size = num - rest;
|
||||||
if (0) {
|
if (0) {
|
||||||
printf("num: %lu, rest: %d, ps: %d\n",
|
printf("num: %lu, rest: %d, ps: %d\n",
|
||||||
(unsigned long)num, niseq->arg_rest, pack_size);
|
(unsigned long)num, niseq->arg_rest, pack_size);
|
||||||
}
|
}
|
||||||
if (pack_size < 0) {
|
if (pack_size < 0) {
|
||||||
rb_raise(rb_eArgError,
|
rb_raise(rb_eArgError,
|
||||||
"wrong number of arguments (%lu for %d)",
|
"wrong number of arguments (%lu for %d)",
|
||||||
(unsigned long)num, rest - niseq->arg_opts);
|
(unsigned long)num, rest - niseq->arg_opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* def m(x,y,z,*a) =>
|
* def m(x,y,z,*a) =>
|
||||||
* x, y, z, a, b, c <SP> => x, y, z, [a,b,c], <SP>
|
* x, y, z, a, b, c <SP> => x, y, z, [a,b,c], <SP>
|
||||||
*/
|
*/
|
||||||
rsp[1 + rest] = rb_ary_new4(pack_size, &rsp[1 + rest]);
|
rsp[1 + rest] = rb_ary_new4(pack_size, &rsp[1 + rest]);
|
||||||
sp = &rsp[2 + rest];
|
sp = &rsp[2 + rest];
|
||||||
num = rest + 1;
|
num = rest + 1;
|
||||||
clear_local_size = niseq->local_size - rest - 1;
|
clear_local_size = niseq->local_size - rest - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* block argument */
|
/* block argument */
|
||||||
if (niseq->arg_block != 0) {
|
if (niseq->arg_block != 0) {
|
||||||
VALUE arg_block_val = Qnil;
|
VALUE arg_block_val = Qnil;
|
||||||
|
|
||||||
if (!((niseq->arg_rest && num == niseq->arg_rest) ||
|
if (!((niseq->arg_rest && num == niseq->arg_rest) ||
|
||||||
(niseq->arg_opts
|
(niseq->arg_opts
|
||||||
&& num == niseq->argc + niseq->arg_opts - 1)
|
&& num == niseq->argc + niseq->arg_opts - 1)
|
||||||
|| num == niseq->argc)) {
|
|| num == niseq->argc)) {
|
||||||
rb_raise(rb_eArgError,
|
rb_raise(rb_eArgError,
|
||||||
"wrong number of arguments (%lu for %d)",
|
"wrong number of arguments (%lu for %d)",
|
||||||
(unsigned long)num, niseq->argc);
|
(unsigned long)num, niseq->argc);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blockptr) {
|
if (blockptr) {
|
||||||
/* make Proc object */
|
/* make Proc object */
|
||||||
if (blockptr->proc == 0) {
|
if (blockptr->proc == 0) {
|
||||||
yarv_proc_t *proc;
|
yarv_proc_t *proc;
|
||||||
reg_cfp->sp = sp;
|
reg_cfp->sp = sp;
|
||||||
arg_block_val = th_make_proc(th, GET_CFP(), blockptr);
|
arg_block_val = th_make_proc(th, GET_CFP(), blockptr);
|
||||||
GetProcPtr(arg_block_val, proc);
|
GetProcPtr(arg_block_val, proc);
|
||||||
blockptr = &proc->block;
|
blockptr = &proc->block;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
arg_block_val = blockptr->proc;
|
arg_block_val = blockptr->proc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rsp[1 + niseq->arg_block - 1] = arg_block_val;
|
rsp[1 + niseq->arg_block - 1] = arg_block_val;
|
||||||
sp++;
|
sp++;
|
||||||
clear_local_size--;
|
clear_local_size--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* stack overflow check */
|
/* stack overflow check */
|
||||||
if (CHECK_STACK_OVERFLOW(th, GET_CFP(), niseq->stack_max + 0x100)) {
|
if (CHECK_STACK_OVERFLOW(th, GET_CFP(), niseq->stack_max + 0x100)) {
|
||||||
rb_exc_raise(sysstack_error);
|
rb_exc_raise(sysstack_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < clear_local_size; i++) {
|
for (i = 0; i < clear_local_size; i++) {
|
||||||
*sp++ = Qnil;
|
*sp++ = Qnil;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
if (0 && (flag & VM_CALL_TAILCALL_BIT)) {
|
if (0 && (flag & VM_CALL_TAILCALL_BIT)) {
|
||||||
th->cfp++;
|
th->cfp++;
|
||||||
push_frame(th, niseq, FRAME_MAGIC_METHOD,
|
push_frame(th, niseq, FRAME_MAGIC_METHOD,
|
||||||
recv, (VALUE) blockptr,
|
recv, (VALUE) blockptr,
|
||||||
niseq->iseq_encoded + opt_pc, sp, 0, 0);
|
niseq->iseq_encoded + opt_pc, sp, 0, 0);
|
||||||
}
|
}
|
||||||
else if (0 &&
|
else if (0 &&
|
||||||
(flag & VM_CALL_TAILRECURSION_BIT) && niseq == GET_ISEQ()) {
|
(flag & VM_CALL_TAILRECURSION_BIT) && niseq == GET_ISEQ()) {
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
GET_CFP()->self = recv;
|
GET_CFP()->self = recv;
|
||||||
SET_LFP(sp);
|
SET_LFP(sp);
|
||||||
SET_DFP(sp);
|
SET_DFP(sp);
|
||||||
*sp++ = (VALUE) blockptr;
|
*sp++ = (VALUE) blockptr;
|
||||||
reg_cfp->sp = sp;
|
reg_cfp->sp = sp;
|
||||||
reg_cfp->bp = sp;
|
reg_cfp->bp = sp;
|
||||||
SET_PC(niseq->iseq_encoded + opt_pc);
|
SET_PC(niseq->iseq_encoded + opt_pc);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
push_frame(th, niseq,
|
push_frame(th, niseq,
|
||||||
FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
|
FRAME_MAGIC_METHOD, recv, (VALUE) blockptr,
|
||||||
niseq->iseq_encoded + opt_pc, sp, 0, 0);
|
niseq->iseq_encoded + opt_pc, sp, 0, 0);
|
||||||
reg_cfp->sp = rsp;
|
reg_cfp->sp = rsp;
|
||||||
}
|
}
|
||||||
RESTORE_REGS();
|
RESTORE_REGS();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MACRO macro_eval_invoke_method(recv, klass, id, num, mn, blockptr)
|
MACRO macro_eval_invoke_method(recv, klass, id, num, mn, blockptr)
|
||||||
{
|
{
|
||||||
/* method missing */
|
/* method missing */
|
||||||
if (mn == 0) {
|
if (mn == 0) {
|
||||||
/* temporarily */
|
/* temporarily */
|
||||||
if (id == idMethodMissing) {
|
if (id == idMethodMissing) {
|
||||||
rb_bug("method missing");
|
rb_bug("method missing");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int stat = 0;
|
int stat = 0;
|
||||||
if (flag & VM_CALL_VCALL_BIT) {
|
if (flag & VM_CALL_VCALL_BIT) {
|
||||||
stat |= NOEX_VCALL;
|
stat |= NOEX_VCALL;
|
||||||
}
|
}
|
||||||
if (flag & VM_CALL_SUPER_BIT) {
|
if (flag & VM_CALL_SUPER_BIT) {
|
||||||
stat |= NOEX_SUPER;
|
stat |= NOEX_SUPER;
|
||||||
}
|
}
|
||||||
val = eval_method_missing(th, id, recv, num, blockptr, stat);
|
val = eval_method_missing(th, id, recv, num, blockptr, stat);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!(flag & VM_CALL_FCALL_BIT) &&
|
else if (!(flag & VM_CALL_FCALL_BIT) &&
|
||||||
(mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) {
|
(mn->nd_noex & NOEX_MASK) & NOEX_PRIVATE) {
|
||||||
int stat = NOEX_PRIVATE;
|
int stat = NOEX_PRIVATE;
|
||||||
if (flag & VM_CALL_VCALL_BIT) {
|
if (flag & VM_CALL_VCALL_BIT) {
|
||||||
stat |= NOEX_VCALL;
|
stat |= NOEX_VCALL;
|
||||||
}
|
}
|
||||||
val = eval_method_missing(th, id, recv, num, blockptr, stat);
|
val = eval_method_missing(th, id, recv, num, blockptr, stat);
|
||||||
}
|
}
|
||||||
else if ((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) {
|
else if ((mn->nd_noex & NOEX_MASK) & NOEX_PROTECTED) {
|
||||||
VALUE defined_class = mn->nd_clss;
|
VALUE defined_class = mn->nd_clss;
|
||||||
|
|
||||||
if (TYPE(defined_class) == T_ICLASS) {
|
if (TYPE(defined_class) == T_ICLASS) {
|
||||||
defined_class = RBASIC(defined_class)->klass;
|
defined_class = RBASIC(defined_class)->klass;
|
||||||
}
|
}
|
||||||
if (!rb_obj_is_kind_of(GET_SELF(), rb_class_real(defined_class))) {
|
if (!rb_obj_is_kind_of(GET_SELF(), rb_class_real(defined_class))) {
|
||||||
val =
|
val =
|
||||||
eval_method_missing(th, id, recv, num, blockptr,
|
eval_method_missing(th, id, recv, num, blockptr,
|
||||||
NOEX_PROTECTED);
|
NOEX_PROTECTED);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
goto INSN_LABEL(normal_method_dispatch);
|
goto INSN_LABEL(normal_method_dispatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
NODE *node;
|
NODE *node;
|
||||||
INSN_LABEL(normal_method_dispatch):
|
INSN_LABEL(normal_method_dispatch):
|
||||||
|
|
||||||
node = mn->nd_body;
|
node = mn->nd_body;
|
||||||
switch (nd_type(node)) {
|
switch (nd_type(node)) {
|
||||||
case YARV_METHOD_NODE:{
|
case YARV_METHOD_NODE:{
|
||||||
macro_eval_invoke_func(node->nd_body, recv, klass,
|
macro_eval_invoke_func(node->nd_body, recv, klass,
|
||||||
blockptr, num);
|
blockptr, num);
|
||||||
NEXT_INSN();
|
NEXT_INSN();
|
||||||
}
|
}
|
||||||
case NODE_CFUNC:{
|
case NODE_CFUNC:{
|
||||||
macro_eval_invoke_cfunc(num, id, recv, klass, node, blockptr);
|
macro_eval_invoke_cfunc(num, id, recv, klass, node, blockptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NODE_ATTRSET:{
|
case NODE_ATTRSET:{
|
||||||
val = rb_ivar_set(recv, node->nd_vid, TOPN(0));
|
val = rb_ivar_set(recv, node->nd_vid, TOPN(0));
|
||||||
POPN(2);
|
POPN(2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NODE_IVAR:{
|
case NODE_IVAR:{
|
||||||
val = rb_ivar_get(recv, node->nd_vid);
|
val = rb_ivar_get(recv, node->nd_vid);
|
||||||
POP();
|
POP();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NODE_BMETHOD:{
|
case NODE_BMETHOD:{
|
||||||
VALUE *argv = GET_SP() - num;
|
VALUE *argv = GET_SP() - num;
|
||||||
val = th_invoke_bmethod(th, id, node->nd_cval,
|
val = th_invoke_bmethod(th, id, node->nd_cval,
|
||||||
recv, klass, num, argv);
|
recv, klass, num, argv);
|
||||||
INC_SP(-num-1);
|
INC_SP(-num-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NODE_ZSUPER:{
|
case NODE_ZSUPER:{
|
||||||
klass = RCLASS(mn->nd_clss)->super;
|
klass = RCLASS(mn->nd_clss)->super;
|
||||||
mn = rb_method_node(klass, id);
|
mn = rb_method_node(klass, id);
|
||||||
|
|
||||||
if (mn != 0) {
|
if (mn != 0) {
|
||||||
goto INSN_LABEL(normal_method_dispatch);
|
goto INSN_LABEL(normal_method_dispatch);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
goto LABEL_IS_SC(start_method_dispatch);
|
goto LABEL_IS_SC(start_method_dispatch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case NODE_SCOPE:{
|
case NODE_SCOPE:{
|
||||||
dpi(id);
|
dpi(id);
|
||||||
SDR();
|
SDR();
|
||||||
rb_bug("eval_invoke_method: NODE_SCOPE should not be appear");
|
rb_bug("eval_invoke_method: NODE_SCOPE should not be appear");
|
||||||
/* unreachable */
|
/* unreachable */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:{
|
default:{
|
||||||
printf("node: %s\n", node_name(nd_type(node)));
|
printf("node: %s\n", node_name(nd_type(node)));
|
||||||
rb_bug("eval_invoke_method: unreachable");
|
rb_bug("eval_invoke_method: unreachable");
|
||||||
/* unreachable */
|
/* unreachable */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,47 +1,47 @@
|
|||||||
/*-*-c-*-*/
|
/*-*-c-*-*/
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
|
||||||
vm_opts.h.base - VM optimize option
|
vm_opts.h.base - VM optimize option
|
||||||
|
|
||||||
$Author: $
|
$Author$
|
||||||
$Date: $
|
$Date$
|
||||||
|
|
||||||
Copyright (C) 2004-2006 Koichi Sasada
|
Copyright (C) 2004-2006 Koichi Sasada
|
||||||
|
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
|
|
||||||
#ifndef VM_OPTS_H_INCLUDED
|
#ifndef VM_OPTS_H_INCLUDED
|
||||||
#define VM_OPTS_H_INCLUDED
|
#define VM_OPTS_H_INCLUDED
|
||||||
|
|
||||||
/* C compiler depend */
|
/* C compiler depend */
|
||||||
#define OPT_DIRECT_THREADED_CODE 1
|
#define OPT_DIRECT_THREADED_CODE 1
|
||||||
#define OPT_CALL_THREADED_CODE 0
|
#define OPT_CALL_THREADED_CODE 0
|
||||||
|
|
||||||
/* architecture independent */
|
/* architecture independent */
|
||||||
|
|
||||||
/* VM running option */
|
/* VM running option */
|
||||||
#define OPT_CHECKED_RUN 1
|
#define OPT_CHECKED_RUN 1
|
||||||
|
|
||||||
/* at compile */
|
/* at compile */
|
||||||
#define OPT_INLINE_CONST_CACHE 1
|
#define OPT_INLINE_CONST_CACHE 1
|
||||||
#define OPT_PEEPHOLE_OPTIMIZATION 1
|
#define OPT_PEEPHOLE_OPTIMIZATION 1
|
||||||
#define OPT_SPECIALISED_INSTRUCTION 1
|
#define OPT_SPECIALISED_INSTRUCTION 1
|
||||||
|
|
||||||
/* at runtime */
|
/* at runtime */
|
||||||
#define OPT_INLINE_METHOD_CACHE 1
|
#define OPT_INLINE_METHOD_CACHE 1
|
||||||
#define OPT_BLOCKINLINING 0
|
#define OPT_BLOCKINLINING 0
|
||||||
|
|
||||||
/* architecture independent, affects generated code */
|
/* architecture independent, affects generated code */
|
||||||
#define OPT_OPERANDS_UNIFICATION 0
|
#define OPT_OPERANDS_UNIFICATION 0
|
||||||
#define OPT_INSTRUCTIONS_UNIFICATION 0
|
#define OPT_INSTRUCTIONS_UNIFICATION 0
|
||||||
|
|
||||||
/* code generation parameter */
|
/* code generation parameter */
|
||||||
#define OPT_UNIFY_ALL_COMBINATION 0
|
#define OPT_UNIFY_ALL_COMBINATION 0
|
||||||
#define OPT_STACK_CACHING 0
|
#define OPT_STACK_CACHING 0
|
||||||
|
|
||||||
/* misc */
|
/* misc */
|
||||||
#define SUPPORT_JOKE 0
|
#define SUPPORT_JOKE 0
|
||||||
|
|
||||||
#endif /* VM_OPTS_H_INCLUDED */
|
#endif /* VM_OPTS_H_INCLUDED */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user