# CallSiteStorage for \[RubyMethod\]

**URL:** <https://www.ruby-forum.com/t/callsitestorage-for-rubymethod/177464>\
**Category:** IronRuby\
**Created:** [October 18, 2009, 8:14am UTC](https://www.ruby-forum.com/t/callsitestorage-for-rubymethod/177464 "2009-10-18T08:14:37Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![shayfriedman](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbe5ce/32.png) [@shayfriedman](https://www.ruby-forum.com/u/shayfriedman)\
**Post date:** [October 18, 2009, 8:14am UTC](https://www.ruby-forum.com/t/callsitestorage-for-rubymethod/177464/1 "2009-10-18T08:14:37Z")

</div>

Hi,

I’m working on a native extension by writing an IronRuby library in C#.  
I  
hit the wall with the CallSiteStorage parameters that can optionally  
come as  
the first 0 or more parameters for a ruby method.

What are they and what’s their use? I tried to understand that from  
their  
current uses accross the code by I couldn’t understand how IronRuby  
knows  
what to set there.

For example, this is from ArrayOps:  
[RubyMethod(“sort”)]  
public static object Sort(  
BinaryOpStorage/_!_/ comparisonStorage,  
BinaryOpStorage/_!_/ lessThanStorage,  
BinaryOpStorage/_!_/ greaterThanStorage,  
BlockParam block, RubyArray/_!_/ self) {  
…  
…  
}

How does IronRuby knows that the first should be a comparison storage,  
the  
second a less-than storage and the third a greater-than storage? is it  
because of the name of the parameter?

Thanks!  
Shay.

---

<div class="post-metadata">

**Author:** ![shayfriedman](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbe5ce/32.png) [@shayfriedman](https://www.ruby-forum.com/u/shayfriedman)\
**Post date:** [October 18, 2009, 3:59pm UTC](https://www.ruby-forum.com/t/callsitestorage-for-rubymethod/177464/2 "2009-10-18T15:59:21Z")

</div>

A dynamic call site is an object that takes a certain number of  
arguments and a kind of description of how to combine those arguments  
into a result. The “description” (also known as the call site binder)  
generates code that is stored in the call site and keyed on some  
property of the arguments – usually the type. So a call site that’s  
used to perform a “less than” operation must be attached to code that  
knows how to look at two arguments and generate IL which will determine  
whether the first arg is less than the second one (or, if the comparison  
is not valid, IL which will throw an exception).

Now let’s say you have a bit of Ruby that says “c = a \< b”. When the  
IronRuby compiler generates code for this, it doesn’t know what the  
types of “a” and “b” are, so it can’t emit the actual comparison.  
Instead, it creates a call site that takes two arguments and returns a  
result, and it attaches this call site to a binder that says “call the \<  
function that’s defined on the first object”. The first time the code is  
executed, a = 1 and b = 3. The binder looks at the type of a and  
determines that it should call Fixnum.\<, so it creates code in the form  
of a delegate which will do that (let’s name this “CALL1”), and will  
store that delegate in the call site along with a test (“TEST1”) which  
indicates when that delegate is valid.

The next time the code is executed, a = 3 and b = 7. The call site  
executes TEST1, which returns a positive result so it uses CALL1 to  
execute the comparison. The binder does not get involved.

The third time the code is executed, a = “hello” and b = “world”. TEST1  
fails, so the call site asks the binder to analyze the new situation and  
come up with a TEST2 and CALL2 that will call String.\< for an argument  
of type string.

All of this is basically DLR 101, so I’m sorry if it’s stuff you already  
know :).

Now it should be pretty obvious that a call site’s performance degrades  
as it sees a greater variety of types. The site has more and more TEST  
methods to run before it gets a positive result or knows that it has to  
fall back to the binder to generate new code.

Consider a method like Array.sort. This method needs to perform  
comparisons on individual array elements of arbitrary type. That means  
that a dynamic call site needs to be involved. In earlier versions of  
IronRuby, we only had two choices – use a single call site that’s  
shared between all calls to Array.sort, or create a new site each time  
sort is called. The former approach suffers from the problem of “going  
megamorphic”, that is, having too many tests to be called for each  
comparison. But with the latter, we lose out on some efficiency because  
we need to create a new call site and run the binder code at least once  
for every call to sort.

The CallSiteStorage mechanism adds a third option. It allows the library  
author to push the location of the call site cache up to the place where  
Array.sort is actually called. This then creates a situation that is  
much more like the one for “c = a \< b”; there’s a one-for-one  
relationship between the call site in user code and the call site cache.  
This is a good level for caching, because any given array in user code  
that calls “sort” is very likely to contain elements of only a single  
type or small number of types.

So to answer your questions more specifically,

1. The IronRuby compiler automatically creates three BinaryOpStorage  
objects for each call to Array.sort – one for each of the three  
parameters which have that type – and emits code to insert those  
parameter onto the call stack before calling ArrayOps.Sort.
2. The BinaryOpStorage object is not tied to a specific operation at  
creation; it’s just a cache. It’s how the BinaryOpStorage is used that  
determines the kind of code stored in the cache.
3. Specifically, if you trace the code path into Protocols.Compare and  
Protocols.ConvertCompareResult, you’ll see that these storages are  
initialized with calls to “\<=\>”, “\<” and “\>”, respectively.
4. The names of the parameters are irrelevant. 🙂

There’s a general lesson here – the DLR is like porridge; it’s best  
when it’s neither too hot nor too cold.

From: removed\_email\_address@domain.invalid  
[[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)] On Behalf Of Shay F.  
Sent: Saturday, October 17, 2009 11:14 PM  
To: removed\_email\_address@domain.invalid  
Subject: [Ironruby-core] CallSiteStorage for [RubyMethod]

Hi,

I’m working on a native extension by writing an IronRuby library in C#.  
I hit the wall with the CallSiteStorage parameters that can optionally  
come as the first 0 or more parameters for a ruby method.

What are they and what’s their use? I tried to understand that from  
their current uses accross the code by I couldn’t understand how  
IronRuby knows what to set there.

For example, this is from ArrayOps:  
[RubyMethod(“sort”)]  
public static object Sort(  
BinaryOpStorage/_!_/ comparisonStorage,  
BinaryOpStorage/_!_/ lessThanStorage,  
BinaryOpStorage/_!_/ greaterThanStorage,  
BlockParam block, RubyArray/_!_/ self) {  
…  
…  
}

How does IronRuby knows that the first should be a comparison storage,  
the second a less-than storage and the third a greater-than storage? is  
it because of the name of the parameter?

Thanks!  
Shay.

–

---

<div class="post-metadata">

**Author:** ![shayfriedman](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbe5ce/32.png) [@shayfriedman](https://www.ruby-forum.com/u/shayfriedman)\
**Post date:** [October 19, 2009, 11:46am UTC](https://www.ruby-forum.com/t/callsitestorage-for-rubymethod/177464/3 "2009-10-19T11:46:26Z")

</div>

Thanks so much Curt for the detailed reply!

Shay.

---

<div class="post-metadata">

**Author:** ![shayfriedman](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/s/bbe5ce/32.png) [@shayfriedman](https://www.ruby-forum.com/u/shayfriedman)\
**Post date:** [October 19, 2009, 3:24pm UTC](https://www.ruby-forum.com/t/callsitestorage-for-rubymethod/177464/4 "2009-10-19T15:24:47Z")

</div>

Glad you enjoyed it!

One small correction: ignore the specific usage of the word “delegate”  
in the second paragraph. The gist is correct, but the technical details  
are different. “Delegate” was left over from an earlier revision of the  
text.

From: removed\_email\_address@domain.invalid  
[[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)] On Behalf Of Shay F.  
Sent: Monday, October 19, 2009 2:30 AM  
To: removed\_email\_address@domain.invalid  
Subject: Re: [Ironruby-core] CallSiteStorage for [RubyMethod]

Thanks so much Curt for the detailed reply!

Shay.  
On Sun, Oct 18, 2009 at 3:52 PM, Curt H.  
\<removed\_email\_address@domain.invalid[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)\> wrote:  
A dynamic call site is an object that takes a certain number of  
arguments and a kind of description of how to combine those arguments  
into a result. The “description” (also known as the call site binder)  
generates code that is stored in the call site and keyed on some  
property of the arguments – usually the type. So a call site that’s  
used to perform a “less than” operation must be attached to code that  
knows how to look at two arguments and generate IL which will determine  
whether the first arg is less than the second one (or, if the comparison  
is not valid, IL which will throw an exception).

Now let’s say you have a bit of Ruby that says “c = a \< b”. When the  
IronRuby compiler generates code for this, it doesn’t know what the  
types of “a” and “b” are, so it can’t emit the actual comparison.  
Instead, it creates a call site that takes two arguments and returns a  
result, and it attaches this call site to a binder that says “call the \<  
function that’s defined on the first object”. The first time the code is  
executed, a = 1 and b = 3. The binder looks at the type of a and  
determines that it should call Fixnum.\<, so it creates code in the form  
of a delegate which will do that (let’s name this “CALL1”), and will  
store that delegate in the call site along with a test (“TEST1”) which  
indicates when that delegate is valid.

The next time the code is executed, a = 3 and b = 7. The call site  
executes TEST1, which returns a positive result so it uses CALL1 to  
execute the comparison. The binder does not get involved.

The third time the code is executed, a = “hello” and b = “world”. TEST1  
fails, so the call site asks the binder to analyze the new situation and  
come up with a TEST2 and CALL2 that will call String.\< for an argument  
of type string.

All of this is basically DLR 101, so I’m sorry if it’s stuff you already  
know :).

Now it should be pretty obvious that a call site’s performance degrades  
as it sees a greater variety of types. The site has more and more TEST  
methods to run before it gets a positive result or knows that it has to  
fall back to the binder to generate new code.

Consider a method like Array.sort. This method needs to perform  
comparisons on individual array elements of arbitrary type. That means  
that a dynamic call site needs to be involved. In earlier versions of  
IronRuby, we only had two choices – use a single call site that’s  
shared between all calls to Array.sort, or create a new site each time  
sort is called. The former approach suffers from the problem of “going  
megamorphic”, that is, having too many tests to be called for each  
comparison. But with the latter, we lose out on some efficiency because  
we need to create a new call site and run the binder code at least once  
for every call to sort.

The CallSiteStorage mechanism adds a third option. It allows the library  
author to push the location of the call site cache up to the place where  
Array.sort is actually called. This then creates a situation that is  
much more like the one for “c = a \< b”; there’s a one-for-one  
relationship between the call site in user code and the call site cache.  
This is a good level for caching, because any given array in user code  
that calls “sort” is very likely to contain elements of only a single  
type or small number of types.

So to answer your questions more specifically,

1. The IronRuby compiler automatically creates three BinaryOpStorage  
objects for each call to Array.sort – one for each of the three  
parameters which have that type – and emits code to insert those  
parameter onto the call stack before calling ArrayOps.Sort.
2. The BinaryOpStorage object is not tied to a specific operation at  
creation; it’s just a cache. It’s how the BinaryOpStorage is used that  
determines the kind of code stored in the cache.
3. Specifically, if you trace the code path into Protocols.Compare and  
Protocols.ConvertCompareResult, you’ll see that these storages are  
initialized with calls to “\<=\>”, “\<” and “\>”, respectively.
4. The names of the parameters are irrelevant. 🙂

There’s a general lesson here – the DLR is like porridge; it’s best  
when it’s neither too hot nor too cold.

From:  
removed\_email\_address@domain.invalid[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
[[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)]  
On Behalf Of Shay F.  
Sent: Saturday, October 17, 2009 11:14 PM  
To: removed\_email\_address@domain.invalid[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
Subject: [Ironruby-core] CallSiteStorage for [RubyMethod]

Hi,

I’m working on a native extension by writing an IronRuby library in C#.  
I hit the wall with the CallSiteStorage parameters that can optionally  
come as the first 0 or more parameters for a ruby method.

What are they and what’s their use? I tried to understand that from  
their current uses accross the code by I couldn’t understand how  
IronRuby knows what to set there.

For example, this is from ArrayOps:  
[RubyMethod(“sort”)]  
public static object Sort(  
BinaryOpStorage/_!_/ comparisonStorage,  
BinaryOpStorage/_!_/ lessThanStorage,  
BinaryOpStorage/_!_/ greaterThanStorage,  
BlockParam block, RubyArray/_!_/ self) {  
…  
…  
}

How does IronRuby knows that the first should be a comparison storage,  
the second a less-than storage and the third a greater-than storage? is  
it because of the name of the parameter?

Thanks!  
Shay.

## –

Shay F.  
Author of IronRuby Unleashed  
[http://www.IronShay.com](http://www.IronShay.com)  
Follow me: [http://twitter.com/ironshay](http://twitter.com/ironshay)

* * *

Ironruby-core mailing list  
removed\_email\_address@domain.invalid[mailto:removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
[http://rubyforge.org/mailman/listinfo/ironruby-core](http://rubyforge.org/mailman/listinfo/ironruby-core)

–
