In this chapter we will talk about methods and start exploring.
This chapter is a method call and talk to both the method of defining one's relationships, Such a variety of "argument" will come out. So, so ambiguously Term to decide exactly where it can get to it.
m (a) # a "typical argument" m (* list) # list is "an array of arguments" m (& block) # block the "block argument" def m (a) # a "normal parameters" def m (a = nil) # a "parameter options", nil, "the default value" def m (* rest) # rest is "rest parameters" def m (& block) # block the "block parameters"
YOUSURUNI to pass all the "arguments", it will receive all the "parameters" Each type of adjectives one, they say.
However, I just mentioned. "Block argument" and "block parameters" Next, in the case of the block will be dealing with.
NODE_CALL nd_mid = 9049 (method) nd_recv: NODE_VCALL nd_mid = 9617 (obj) nd_args: NODE_ARRAY [ 0: NODE_LIT nd_lit = 7: Fixnum 1: NODE_LIT nd_lit = 8: Fixnum ]
Node is a method call
NODE_ARRAY is a list of arguments that are stored.
In addition to this method is called as a node
NODE_FCALL is "
method (args) " format,
NODE_VCALL is local
The same variables "
method " in the form of response to the call. It is not really
VCALL is one that can be put together,
VCALL when the argument to prepare
No need for a code that the memory and only in order to save time
rb_eval () ,
NODE_CALL handlers to look at.
2745 case NODE_CALL: (2746 2747 VALUE recv; 2748 int argc; VALUE * argv; / * used in SETUP_ARGS * / 2749 TMP_PROTECT; 2750 2751 BEGIN_CALLARGS; 2752 recv = rb_eval (self, node-> nd_recv); 2753 SETUP_ARGS (node-> nd_args); 2754 END_CALLARGS; 2755 2756 SET_CURRENT_SOURCE (); 2757 result = rb_call (CLASS_OF (recv), recv, node-> nd_mid, argc, argv, 0); 2758) 2759 break; (eval.c)
There are three macro issues,
BEGIN_CALLARGS SETUP_ARGS () END_CALLARGS .
rb_eval () receiver evaluation
rb_call () 起動らしいhad a method, the three
Macro assessment of the argument that it's tough, and you can imagine the sort of
Is actually what you are doing?
Iterator to talk to them and not hard to understand, the next chapter in the block,
Once explained. This is
SETUP_ARGS () with the investigation only.
SETUP_ARGS () is a method to assess the macro part of the argument. This macro
, The original program as the comments,
argv a variable
So it must be defined in advance. Also
TMP_ALLOC () since they use
TMP_PROTECT should have been using.
So the following is formulaic.
int argc; VALUE * argv; / * used in SETUP_ARGS * / TMP_PROTECT; SETUP_ARGS (args_node);
args_node is the method of argument (to represent node), which evaluated
The array of different values,
argv stored. Let's not look at.
1780 # define SETUP_ARGS (anode) do (\ 1781 NODE * n = anode; \ 1782 if (! N) (\ no argument 1783 argc = 0; \ 1784 argv = 0; \ 1785) \ 1786 else if (nd_type (n) == NODE_ARRAY) (\ usually only argument 1787 argc = n-> nd_alen; \ 1788 if (argc> 0) (\ arguments in 1789 int i; \ 1790 n = anode; \ 1791 argv = TMP_ALLOC (argc); \ 1792 for (i = 0; i
nd_head); \ 1794 n = n-> nd_next; \ 1795) \ 1796) \ 1797 else (\ no argument 1798 argc = 0; \ 1799 argv = 0; \ 1800) \ 1801) \ 1802 else (\ array of arguments and 1803 VALUE args = rb_eval (self, n); \ argument for the block 1804 if (TYPE (args)! = T_ARRAY) \ 1805 args = rb_ary_to_ary (args); \ 1806 argc = RARRAY (args) -> len; \ 1807 argv = ALLOCA_N (VALUE, argc); \ 1808 MEMCPY (argv, RARRAY (args) -> ptr, VALUE, argc); \ 1809) \ 1810) while (0) (eval.c)
Rather lengthy, and three branches to the sea because TAISHITE actually does harm. Each branch is the meaning of the comments earlier in the street.
None of the arguments does not matter as the rest of the two branches have a similar thing Do you have. I can roughly say that the three phases,
. I try writing the code. (Incidentally format and a little earlier).
/***** Else if clause, argc! = 0 *****/ int i; n = anode; argv = TMP_ALLOC (argc); / * 1 * / for (i = 0; i
nd_head); / * 2,3 * / n = n-> nd_next; ) /***** Else clause *****/ VALUE args = rb_eval (self, n); / * 2 * / if (TYPE (args)! = T_ARRAY) args = rb_ary_to_ary (args); argc = RARRAY (args) -> len; argv = ALLOCA_N (VALUE, argc); / * 1 * / MEMCPY (argv, RARRAY (args) -> ptr, VALUE, argc); / * 3 * /
else if side, it is
TMP_ALLOC () , but with
ALLOCA_N () , that is normal
alloca () Why are you using?
C_ALLOCA environment is
alloca () is
malloc () equal to it, is dangerous and
This is "
else side of the argument value is
args it is," It is
Points. If the figure as shown in Figure 1.
Figure 1: Even if you do not heap
It is also one of
VALUE on the stack if there through the chain marked.
VALUE stack to stop the Spanish beard anchor (anchor) like
Role, namely "anchor
VALUE " said.
else side, it is
args to anchor
VALUE is not a term coined made.
SETUP_ARGS () If anything is wrong way. From here you can go back to the main topic. Method
To start the function
rb_call () . If you are a real exception to the above見付からなかった
You look at the code, but omit all by example.
static VALUE rb_call (klass, recv, mid, argc, argv, scope) VALUE klass, recv; ID mid; int argc; const VALUE * argv; int scope; ( NODE * body; int noex; ID id = mid; struct cache_entry * ent; / * * Method cache / ent = cache + EXPR1 (klass, mid); if (ent-> mid == mid & & ent-> klass == klass) ( / * * Cache hit / klass = ent-> origin; id = ent-> mid0; noex = ent-> noex; body = ent-> method; ) else ( / * Miss cache. Execute search * / body = rb_get_method_body (& klass, & id, & noex); ) / *…… Check the visibility…… * / return rb_call0 (klass, recv, mid, id, argc, argv, body, noex & NOEX_UNDEF); )
The basic method is exploring how the object, in Chapter 2. Super
TADORI class while
m_tbl You can search. Is to do it
search_method () .
That's right, the principle is, however, but to actually run the stage and method calls
How many times each time searching for the hash to pull his speed is too late. To break
ruby , once called the method is similar to the cache
. The method is called just once, and we can often invoked, that
Experience on the facts as known, and the cache hit rate is high.
The cache, which is索い
rb_call () the first half. This
ent = cache + EXPR1 (klass, mid);
Only one line has been cached. The mechanism is more to look after.
When the cache is out of the next
rb_get_method_body () class tree in an honest way
Search the results of the cache TSUIDENI keep it that.
Search the entire flow chart should look like Figure 2.
Figure 2: The search method
Then method of cash, let's take a closer look at the structure.
180 # define CACHE_SIZE 0x800 181 # define CACHE_MASK 0x7ff 182 # define EXPR1 (c, m) ((((c)>> 3) ^ (m)) & CACHE_MASK) 183 184 struct cache_entry (/ * method hash table. * / 185 ID mid; / * method's id * / 186 ID mid0; / * method's original id * / 187 VALUE klass; / * receiver's class * / 188 VALUE origin; / * where method defined * / 189 NODE * method; 190 int noex; 191); 192 193 static struct cache_entry cache [CACHE_SIZE]; (eval.c)
In a nutshell mechanisms to hash tables. And the principle of the hash table YOUSURUNI table an array of search indexing convert it. Resona The time required to be at least three. An array of data, key, and hash Function.
This is the first array is
struct cache_entry array. Kula and methods
Su and uniquely determined by the method name only from the two key calculation of the hash
Be. After the cache from an array of key index (
0x7ff ) live
Sung to make a hash function. That's
EXPR1 () . Arguments
c of the class
m is the method name (
ID ) (see Figure 3).
Figure 3: Cash method
EXPR1 () hash function is completely different because of what method is really a coincidence
To generate the same index that can result possible. However, this is just an interesting
SHU collision because it is not the problem. But work is only a little slower.
By the way, the method is actually how much cash is the effect? "…… It is known that" they are also unconvinced. Measuring your own.
|LALR (1) generated parser|| ||99.9%|
|generated MERUSUREDDO||certain mailers||99.1%|
|document generation|| ||97.8%|
What the experiment in all three cases hit a record rate of 95% or more. This is Great. Apparently, "…… it is known that" the effect of Outstanding.
Now the method for many reasons, but where to start with Tasoritsuku this
rb_call0 () is
And big. It is more than 200 lines on the page will be five or six pages?
Anyway, the viewer, at once lay out the paper and it would be disastrous split in detail
While we go to it. From the first snap.
4482 static VALUE 4483 rb_call0 (klass, recv, id, oid, argc, argv, body, nosuper) 4484 VALUE klass, recv; 4485 ID id; 4486 ID oid; 4487 int argc; / * OK * / 4488 VALUE * argv; / * OK * / 4489 NODE * body; / * OK * / 4490 int nosuper; (4491 4492 NODE * b2; / * OK * / 4493 volatile VALUE result = Qnil; 4494 int itr; 4495 static int tick; 4496 TMP_PROTECT; 4497 4498 switch (ruby_iter-> iter) ( 4499 case ITER_PRE: 4500 itr = ITER_CUR; 4501 break; 4502 case ITER_CUR: 4503 default: 4504 itr = ITER_NOT; 4505 break; 4506) 4507 4508 if ((+ + tick & 0xff) == 0) ( 4509 CHECK_INTS; / * better than nothing * / 4510 stack_check (); 4511) 4512 PUSH_ITER (itr); 4513 PUSH_FRAME (); 4514 4515 ruby_frame-> last_func = id; 4516 ruby_frame-> orig_func = oid; 4517 ruby_frame-> last_class = nosuper? 0: klass; 4518 ruby_frame-> self = recv; 4519 ruby_frame-> argc = argc; 4520 ruby_frame-> argv = argv; 4521 4522 switch (nd_type (body)) ( / *…… This treatment…… * / 4698 4699 default: 4700 rb_bug ( "unknown node type% d", nd_type (body)); 4701 break; 4702) 4703 POP_FRAME (); 4704 POP_ITER (); 4705 return result; 4706) (eval.c)
ITER putting in iterator whether this method is ultimately determined. Resona
PUSH_FRAME () , whose value is immediately used to
PUSH_ITER () in front of the
But you have to.
PUSH_FRAME () on the heels of.
And at "…… this treatment……" and I talk about here is Following each node is divided into different startup process.
| ||C defined by the method|
| || |
| || |
| || |
| || no arguments |
| || |
| || |
| ||Ruby method defined by|
This document will not have to explain, but none is so important with scant disregard them
. It is important
NODE_SCOPE , and
536 # define PUSH_FRAME () do (\ 537 struct FRAME _frame; \ 538 _frame.prev = ruby_frame; \ 539 _frame.tmp = 0; \ 540 _frame.node = ruby_current_node; \ 541 _frame.iter = ruby_iter-> iter; \ 542 _frame.cbase = ruby_frame-> cbase; \ 543 _frame.argc = 0; \ 544 _frame.argv = 0; \ 545 _frame.flags = FRAME_ALLOCA; \ 546 ruby_frame = & _frame 548 # define POP_FRAME () \ 549 ruby_current_node = _frame.node; \ 550 ruby_frame = _frame.prev; \ 551) while (0) (eval.c)
FRAME solid place to ensure that the stack you want to see. This is
module_setup () same. The rest is basically normal and only initialization.
If you add one thing,
It shows how the assignment, much?
Of course, "on a stack" shows.
Here's a look at the real number is a lot of writing, but most of
trace_func substantive relationship because it is the end of the line.
case NODE_CFUNC: result = call_cfunc (body-> nd_cfnc, recv, len, argc, argv); break;
call_cfunc () is said……
4394 static VALUE 4395 call_cfunc (func, recv, len, argc, argv) 4396 VALUE (* func) (); 4397 VALUE recv; 4398 int len, argc; 4399 VALUE * argv; (4400 4401 if (len> = 0 & & argc! = Len) ( 4402 rb_raise (rb_eArgError, "wrong number of arguments (% d for% d)", 4403 argc, len); 4404) 4405 4406 switch (len) ( 4407 case -2: 4408 return (* func) (recv, rb_ary_new4 (argc, argv)); 4409 break; 4410 case -1: 4411 return (* func) (argc, argv, recv); 4412 break; 4413 case 0: 4414 return (* func) (recv); 4415 break; 4416 case 1: 4417 return (* func) (recv, argv ); 4418 break; 4419 case 2: 4420 return (* func) (recv, argv , argv ); 4421 break; : : 4475 default: 4476 rb_raise (rb_eArgError, "too many arguments (% d)", len); 4477 break; 4478) 4479 return Qnil; / * not reached * / 4480) (eval.c)
Thus, the argument based on the number of branches. By the way, the argument that the maximum number is 15.
One of them is aware,
NODE_CFUNC when the
VARS not on board
. The method is
C If it is defined in Ruby, so do not use local variables
There is good reason to put it. But at the same time
C from the "current" local variables
To access the previous one and
FRAME local variables that will see it
Mean that. And it actually doing both. For example
NODE_SCOPE Ruby That is defined by the start of the method.
The underlying part of Ruby.
4568 case NODE_SCOPE: (4558 4570 int state; 4571 VALUE * local_vars; / * OK * / 4572 NODE * saved_cref = 0; 4573 4574 PUSH_SCOPE (); 4575 / * (A) CREF transfer * / 4576 if (body-> nd_rval) ( 4577 saved_cref = ruby_cref; 4578 ruby_cref = (NODE *) body-> nd_rval; 4579 ruby_frame-> cbase = body-> nd_rval; 4580) / * (B) ruby_scope-> local_vars initialization * / 4581 if (body-> nd_tbl) ( 4582 local_vars = TMP_ALLOC (body-> nd_tbl  +1); 4583 * local_vars + + = (VALUE) body; 4584 rb_mem_clear (local_vars, body-> nd_tbl ); 4585 ruby_scope-> local_tbl = body-> nd_tbl; 4586 ruby_scope-> local_vars = local_vars; 4587) 4588 else ( 4589 local_vars = ruby_scope-> local_vars = 0; 4590 ruby_scope-> local_tbl = 0; 4591) 4592 b2 = body = body-> nd_next; 4593 4594 PUSH_VARS (); 4595 PUSH_TAG (PROT_FUNC); 4596 4597 if ((state = EXEC_TAG ()) == 0) ( 4598 NODE * node = 0; 4599 int i; / *…… (C) local variable arguments…… * / 4666 if (trace_func) ( 4667 call_trace_func ( "call", b2, recv, id, klass); 4668) 4669 ruby_last_node = b2; / * (D) method bodies * / 4670 result = rb_eval (recv, body); 4671) 4672 else if (state == TAG_RETURN) (/ * return to return * / 4673 result = prot_tag-> retval; 4674 state = 0; 4675) 4676 POP_TAG (); 4677 POP_VARS (); 4678 POP_SCOPE (); 4679 ruby_cref = saved_cref; 4680 if (trace_func) ( 4681 call_trace_func ( "return", ruby_last_node, recv, id, klass); 4682) 4683 switch (state) ( 4684 case 0: 4685 break; 4686 4687 case TAG_RETRY: 4688 if (rb_block_given_p ()) ( 4689 JUMP_TAG (state); 4690) 4691 / * fall through * / 4692 default: 4693 jump_tag_but_local_jump (state); 4694 break; 4695) 4696) 4697 break; (eval.c)
(A) Back at the constant talk
That is the method of entry
(B) is here
module_setup () , did exactly the same.
local_vars array assigned to it. In
PUSH_SCOPE () ,
PUSH_VARS () generated in the scope of local variables is complete. This is after
Exactly the same methods and internal environment
rb_eval () can be.
(C) received a method's arguments set the parameters variable.
YOUSURUNI local variables and parameters of the same variable. Argument
The number of
NODE_ARGS specified in the same honest way I set SHITEYARE.
Further explanation of this immediately. And,
(D) method to run the body. Naturally receiver (
recv ) to
In other words
rb_eval () the first argument. This method is fully launched.
SUTTOBA part of the argument, set a detailed look at the The method of construction before the first trees to see me again.
% Ruby-rnodedump-e 'def m (a) nil end' NODE_SCOPE nd_rval = (null) nd_tbl = 3 [_ ~ a] nd_next: NODE_BLOCK nd_head: NODE_ARGS nd_cnt = 1 nd_rest = -1 nd_opt = (null) nd_next: NODE_BLOCK nd_head: NODE_NEWLINE nd_file = "-e" nd_nth = 1 nd_next: NODE_NIL nd_next = (null)
NODE_ARGS method is to specify the parameters of nodes.
まくっtried to dump some of its members are as follows:
| ||usual number of parameters.|
| || |
| || default option syntax tree to represent the value in it. |
With so much information you need to respond to each parameter variable ID is unique to the local variables
Determined. First one is always 0
$~. The next two from the normal parameters
The number of line up. The parameters are lining up to the next option. PERTH options
The number of parameter
NODE_BLOCK can see in length. The parameters of the rest came after
For example, following the definition,
def m (a, b, c = nil, * rest) lvar1 = nil end
Local variables are as follows ID allocated.
0 1 2 3 4 5 6 $ _ $ ~ A b c rest lvar1
I? Based on this, a look at the code.
4601 if (nd_type (body) == NODE_ARGS) (/ * * No body / 4602 node = body; / * NODE_ARGS * / 4603 body = 0; / * * method bodies / 4604) 4605 else if (nd_type (body) == NODE_BLOCK) (/ * body * / 4606 node = body-> nd_head; / * NODE_ARGS * / 4607 body = body-> nd_next; / * * method bodies / 4608) 4609 if (node) (/ * * some parameters / 4610 if (nd_type (node)! = NODE_ARGS) ( 4611 rb_bug ( "no argument-node"); 4612) 4613 4614 i = node-> nd_cnt; 4615 if (i> argc) ( 4616 rb_raise (rb_eArgError, "wrong number of arguments (% d for% d)", 4617 argc, i); 4618) 4619 if (node-> nd_rest == -1) (/ * rest parameters * / / * * Count the number of parameters / 4620 int opt = i; / * number of parameters (i is nd_cnt) * / 4621 NODE * optnode = node-> nd_opt; 4622 4623 while (optnode) ( 4624 opt + +; 4625 optnode = optnode-> nd_next; 4626) 4627 if (opt
argc = opt; 4632 ruby_frame-> argv = local_vars +2; 4633) 4634 4635 if (local_vars) (/ * * parameters / 4636 if (i> 0) (/ * * normal parameters / 4637 / __ * $ $ to the region in order to dodge +2 * / 4638 MEMCPY (local_vars +2, argv, VALUE, i); 4639) 4640 argv + = i; argc -= i; 4641 if (node-> nd_opt) (/ * * options parameters / 4642 NODE * opt = node-> nd_opt; 4643 4644 while (opt & & argc) ( 4645 assign (recv, opt-> nd_head, * argv, 1); 4646 argv + +; argc -; 4647 opt = opt-> nd_next; 4648) 4649 if (opt) ( 4650 rb_eval (recv, opt); 4651) 4652) 4653 local_vars = ruby_scope-> local_vars; 4654 if (node-> nd_rest> = 0) (/ * rest parameters * / 4655 VALUE v; 4656 / * Exactly zero of the array of arguments to the variable * / 4657 if (argc> 0) 4658 v = rb_ary_new4 (argc, argv); 4659 else 4660 v = rb_ary_new2 (0); 4661 ruby_scope-> local_vars [node-> nd_rest] = v; 4662) 4663) 4664) (eval.c)
Comments from a generous amount ever in looking at and we've been a steady pursuit of ERE if they are doing it.
I was the one
argv to be. rest parameters
Not only update the like, but why not the rest parameters
Need to do?
argv useful to think of things. This is actually a member
super for a man. This means following form.
super is currently running as a method parameter hand over work
KIGA. At that time you can give to
ruby_frame-> argv arguments to keep it
Write back to the original story, rest when you have the parameters
super , the original argument Limited
It is convenient to pass the sort of strike is likely to feel it. Not when the Op
Applications will be assigned after the parameters of what it is I do not think so.
def m (a, b, * rest) Perhaps super # 5, 6, 7, 8 to be passed end m (5, 6, 7, 8) def m (a, b = 6) Perhaps super # 5, 6 to be passed end m (5)
This is "I must be" rather than as either good or specifications, The problem. If you have any method parameters rest of the superclass But the parameters are also believed to rest, compiled after a pass value Inconveniences may become very expensive.
Now, many methods are said to start this story is all over.
After the closing of this chapter is now the subject of
super , looking at implementation
super to respond to the
NODE_SUPER is a simple
NODE_ZSUPER None of the arguments
2780 case NODE_SUPER: 2781 case NODE_ZSUPER: (2782 2783 int argc; VALUE * argv; / * used in SETUP_ARGS * / 2784 TMP_PROTECT; 2785 / * (A) super if you are prohibited * / 2786 if (ruby_frame-> last_class == 0) ( 2787 if (ruby_frame-> orig_func) ( 2788 rb_name_error (ruby_frame-> last_func, 2789 "superclass method`% s' disabled ", 2790 rb_id2name (ruby_frame-> orig_func)); 2791) 2792 else ( 2793 rb_raise (rb_eNoMethodError, "super called outside of method"); 2794) 2795) / * (B) or prepare arguments rating * / 2796 if (nd_type (node) == NODE_ZSUPER) ( 2797 argc = ruby_frame-> argc; 2798 argv = ruby_frame-> argv; 2799) 2800 else ( 2801 BEGIN_CALLARGS; 2802 SETUP_ARGS (node-> nd_args); 2803 END_CALLARGS; 2804) 2805 / * (C) still a mystery PUSH_ITER () * / 2806 PUSH_ITER (ruby_iter-> iter? ITER_PRE: ITER_NOT); 2807 SET_CURRENT_SOURCE (); 2808 result = rb_call (RCLASS (ruby_frame-> last_class) -> super, 2809 ruby_frame-> self, ruby_frame-> orig_func, 2810 argc, argv, 3); 2811 POP_ITER (); 2812) 2813 break; (eval.c)
None of the arguments
ruby_frame-> argv as the argument
Said, but (B) as it emerged.
rb_call () call just before
PUSH_ITER () . This theory is also more
It is not clear, and thus keep the current method was passed along to block
Leave again the following method (that is now called super-class method)
And finally (A)
ruby_frame-> last_class is 0 when
Calling the ban. Error messages are
Must be enabled by rb_enable_super () "
The film is,
rb_enable_super () to call to get the word NARURASHII.
First of all
last_class 0 is what you get when you examine it, I was real
C, defined in the method (
NODE_CFUNC ) and I said to be running.
In addition to such methods
alias or replaced or when the same.
So far, but found that the source code, but insist that read more
Do not know. Since no choice but do not know
ruby log mailing list
Rb_enable_super " discovered in the search. The Mail said the following
String.new method. Of course, to generate a string method
T_STRING to make the structure. Therefore
The receiver is always an instance method
T_STRING is expected to be written.
T_OBJECT to make the structure. ,
String.new to replace the definition
What will become of those.
def String.new super end
As a result of the structure is
T_OBJECT But class is
String , the object is
T_STRING hope that the structure of the writing
How to avoid it, or do I say that a different structure in the hope that the media
Method is described as like I do. But the method is "expected structure"
I have no information, no class. For example
T_STRING how to get in if he could check before calling, but I think that
Is not possible at this time. So as the second best "C from the method defined
super is prohibited, "they have. Then, C-level hierarchical method
Let's lock down, you can make it not. And "absolute
It's okay to
super I hope that "if the
rb_enable_super () to
You should call
super there will be.
YOUSURUNI root of the problem is the structure of the mismatch. AROKESHONFUREMUWAKU occurred in the same issue.
That solution is what should I do or say, the root of the problem, "Kula Is not an instance of the structure not know "to resolve that I do. But it But there is a new API from the need to be more thorough about it compatible with Lose. So right now it is not the final solution is not always .
The original work is Copyright © 2002 - 2004 Minero AOKI.
Translations,  additions,  and graphics by C.E. Thornton
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike2.5 License.