99 lines
3.7 KiB
Plaintext
99 lines
3.7 KiB
Plaintext
= render "pages/rubyx/menu"
|
|
|
|
%h1=title "Dynamic Method resolution"
|
|
|
|
%p
|
|
Dynamic method resolution is the process of finding a method to call.
|
|
The
|
|
=link_to "calling convention" , "calling.html"
|
|
defines how arguments are transferred and control changes and returns.
|
|
|
|
%h2 Resolution in general
|
|
%p
|
|
To determine a Method in Rubyx, we need to determine the
|
|
%b Type.
|
|
%p
|
|
Types store the methods, and with the method name we can then find the appropriate
|
|
Method.
|
|
%p
|
|
Ruby has a fallback for when a method is not found: we then call
|
|
%em method_missing.
|
|
This is defined on Object, and as every object is an object,
|
|
%em method_missing
|
|
is guaranteed to be found.
|
|
%p
|
|
This is the same process for dynamic and static resolution.
|
|
|
|
%h2 Static Resolution
|
|
%p
|
|
The need to resolve a method dynamically stems from an inability to determine
|
|
the Method at compile-time.
|
|
%p
|
|
Currently the only way to be sure of an expressions type, or the only case
|
|
the compiler recognises, is an assignment directly before the call. This
|
|
"types" the variable that is assigned and we can retrieve the method.
|
|
%p
|
|
Off course calls on constants are also recognised. But otherwise
|
|
a dynamic resolution is initiated.
|
|
|
|
%h2 Dynamic Method Resolution
|
|
%p
|
|
When static resolution has failed, the compiler emits code to resolve the
|
|
method at runtime. This process resolves around a cache, and currently a
|
|
cache of one, captured by the class
|
|
=ext_link "CacheEntry" , "https://github.com/ruby-x/rubyx/blob/master/lib/parfait/cache_entry.rb"
|
|
|
|
%h3 Vool
|
|
%p
|
|
Static resolution is done at the Vool level, where the CacheEntry is also created
|
|
and then used as any other constant. Ie there is exactly one CacheEntry for every
|
|
call site (SendStatement).
|
|
%p
|
|
Vool breaks the resolution into it's logical component steps, ie:
|
|
%ul
|
|
%li Check the current type against cached type
|
|
%li Update cached type if needed
|
|
%li Update cached method if needed
|
|
%li Call the cached method
|
|
|
|
Breaking down means that Mom Instructions are emitted to effect the logic above.
|
|
Most of the logic (like the if that is needed) already exists. But the last two
|
|
steps require special instructions described below.
|
|
|
|
%h3 Mom
|
|
%p
|
|
The method cache update described above is basically an assignment where
|
|
we assign the resolved method to the cache. But to do that, we need to finally
|
|
do the method resolution.
|
|
%p
|
|
The implementation of the
|
|
%em ResolveMethod
|
|
is quite a bit longer than most other Mom instructions, but basically does:
|
|
%ul
|
|
%li Load methods from current (cached) type
|
|
%li Enter a while loop until we hit nil (goto NOT_FOUND if nil)
|
|
%li compare the name of the method with the given name and goto OK if equal
|
|
%li get the next method (they too are a linked list) and start at while
|
|
%li NOT_FOUND find method_missing and save in cache (similar process)
|
|
%li OK: save method in cache
|
|
To achieve readable code for this low level assembler programming a DSL is
|
|
used. The
|
|
=ext_link "result", "https://github.com/ruby-x/rubyx/blob/master/lib/mom/instruction/resolve_method.rb#L32"
|
|
is quite understandable.
|
|
|
|
%p
|
|
The actual dynamic call does differ from it's static counterpart, but maybe
|
|
surprising little. In essence both static and dynamic calls:
|
|
%ul
|
|
%li create a label and save the return address
|
|
%li load the methods jump address
|
|
%li swap in the next message, replacing the current
|
|
%li jump to the address
|
|
%p
|
|
The main difference is in loading the method's address (step 2). Where a static
|
|
setup just loads the method constant, the dynamic one load the CacheEntry first, and
|
|
the method from that.
|
|
%br
|
|
That is basically the main difference. Currently (4/18) a FunctionCall/DynamicJump is
|
|
still issued, but they are so similar that they will probably be unified soon.
|