 How many, just out of curiosity when we start, how many people here use more than one ruby? Okay, pretty much everybody. How many people have actually ever tried magla? Okay, a handful. So we'll get started. So back in Valentine's Day in 2008, when we started implementing magla, that was the time Abhi Bryant convinced me that this was like a really easy thing to do, that the object models were similar, and a hundred days later, Abhi and some guys that I, you know, our site had WebRick running and they were running yard benchmarks, we thought, well, surely, you know, this really is pretty easy. And then we discovered that we had only explored the tip of the iceberg, and certainly there was no such thing as the free lunch that Abhi didn't kind of promise. However, there might be, okay, that's not gonna work. However, there might be a free pony. And even if the pony's not obvious, just kind of like the spebsome picture. But in a recent blog post, Rob Hyton wrote, the real reason to play with magla was the free pony. And what he was talking about was the persistence layer in magla. And so before Peter gets to the part talking about how difficult it was getting past this free lunch thing, I'd like to explain a little bit about magla's persistent cache. I kind of wanted to talk about other, you know, more significant things, maybe like profilers and debuggers and object logs and statistics displays and all that stuff. But it really, none of that matters until you get persistence done. And we call it a persistent, we used to call it a persistent cache. I think we quit doing that, but I think I wanna go back to that terminology because magla objects have the same structure and memory and on disk so that when you persist something to disk, it's just a straight line. There's no marshaling, no object relational mapping. And all the, when you get it into the cache and any magla VM running on the same system, either the same machine or another machine, but in the same fabric, all have access to the shared memory to get past access. I think I'll maybe start using the term cache again. So I wanna go back to RailsConf 2008. I'll be, Brian used this familiar magic trick to demo magla persistence. He pulled the rabbit, put into a hat in one Ruby VM, out of the hat in a separate Ruby VM. And but, you know, he didn't really explain how he did it. He just showed it, showed he had enough enough to slaves, but he didn't explain it. So I thought today, I would be like those magicians who rap on other magicians and I'd show you kind of what was going on behind the curtain. So, like all hat tricks, it just starts out with a simple ordinary Ruby hat. I mean, there's nothing here. Initialize this to an empty array, you can put things in it and ask its size. So there's no Ruby then, but there's no magla magic here. Just standard Ruby stuff. Works fine in MRI. And then, the rabbit's even simpler. It's only got one method, it's got an inspect method. And you kind of have to squeeze the rabbit down so it fits into this tiny space so we can sneak it into the hat. But, when it pops out of the hat, you can see that indeed, it is a bunny rabbit. And that's what Abby showed it, RailsConf. But I'm gonna talk a bit about three of the devices in magla that make that possible. And then, I'll show you a quick demo that showed that it actually works. So, the first thing is, first kind of incantation that makes this work kind of like Advocatabra is maglab persistent do. And this provides a way to load classes that then become persistent in maglab and are available to other images. And, you know, without persistence, the bunny and even the hat would kind of go away as soon as I quit running my VM. So, the next trick up our sleeve is called maglab commit transaction. It's got an evil twin called maglab abort transaction, but these basically begin and end in even magic tricks. Not possible to transfer a bunny from one hat to another without committing the transaction first. And maglab transactions, although we call it a cache, it really is database like maglab transactions have acid properties, atomicity, consistency, isolation, and durability, and we'll actually demonstrate that in a minute when I get to the live part of this. So, the third thing I want to talk about is maglab persistent root. This is the cage where we keep the bunny in between tricks. We make sure it doesn't get lost. All it is basically, it's a hash that provides a convenient place to hang a Ruby object that you want to stick around. And persistence is by reachability. So, anything that you attach in this hash, you can get to that object, you can get to any object connected to that object. When everything's totally disconnected from the persistent root, it'll get garbage collected. And you can put any kind of object you want in here. I mean, trees, grass, key value of perish, the blocks, crops, lambdas, it doesn't matter. And I was talking to one of my users last week because it's kind of hard to explain why even people would want to do this. But he said, you know, after about a month of useness, I kind of realized he was what I wasn't doing rather than what I was doing that was interesting. He said, he says, I just wasn't having to think about persistency or anything I wanted to have later. I just kind of stuck it in there. And then I realized I wasn't thinking about the data anymore. So, he think that's the cool part. But the next thing, so if we look at how we turned that simple Ruby hat into a kind of magic hat using these tricks, this is what we do. I mean, basically we do a maglev persistent dude. We load the hat and the rabbit, which is gonna load those classes into the persistent image. We create a hat, that's the first thing a magician is gonna do is create a new hat and commit that transaction. And this will print, you know, kind of for diagnostic purpose here, it'll print through we've created an empty app, which we could delete, but we'll leave it there for purposes of demo. Then the magician would show the audience that the hat is empty, you know. Then the magician's assistant or the magician by some magic is going to put a new rabbit into the hat. Then we go back and show that the rabbit is in the hat and then that's the end of the magic trick. However, what we're gonna do, being the magician who wants to expose stuff, we're gonna persist the prop in the system. That's gonna allow us to look at persistent, this persistent route and see what's in there. And it's fairly simple, it's just a prop of what's the transaction, so we make sure we've got in those current state. And then we just look at either the persistent route or a key that we pass in, doesn't matter. And so we're gonna store this as a prop in the database. I think it's probably very difficult to store a prop in my SQL, you can store restrained prop, presents a prop, but it's not really a prop. So let's see, I'm going to switch to a screen where I can run this live for a minute. Let's see what we can do, see if I can make this work. I can see it, okay. So first thing we're gonna do is I'm gonna fire up IRB and turn that prop into a local variable. So I'm gonna have to type quite so much and we're gonna execute that prop and we're gonna see. There's nothing in the hat but the prop so the magician is not even starting yet. So let's see, let's go over to the magician and what's the magician gonna do? First thing the magician is gonna do is gonna create the hat, okay. And we can go back over here and we can peek again and we can see that yeah, in the persistent route we've now got the prop, we also have the hat and you can see that the hat is empty. So the magician is then gonna, let's see, then we'll do that again. Magician's gonna show that the hat is empty as well. And about this time, the assistant is gonna go over here and add the rabbit to the hat. Now let's go back to, let's go over here first where we can see and let's peek before the magician so we're behind stage and we can see that yeah, we now have the hat and the hat has the rabbit in it. So the magician then shows the hat contents, voila, and the rabbit is there. All of these, anytime I execute one of these I'm firing up a new VM and just executing it from scratch. I don't really need to have the, I don't really need to have separate ones for these but I think it shows better that they are actually separate VMs. So now the assistant's gonna add another hat, another rabbit to the hat. But I'll tell you what let's do, let's mess with their minds a bit up. Okay, I guess it doesn't take me, I guess with the caps off the key, that doesn't work, have a lower case exit. So we've got a maglev server out there running them. It's pit is 33.36, so let's kill it. So this is gonna completely screw up the magician. I mean, we can look here and do status again and you can see maglev's not even running. So the magician goes out here to show the second rabbit. Well, he gets the maglev server's not running, he makes his apologies, starts it up again and here you go. Clear the screen for those who's down at the bottom. Does the show have contents? And now both records are there. Even after we fill a system, start it up completely separate VMs. Because it's not just the data that's the rabbit, the classes there, the properties there, everything that we use is there. Now, but you might ask, where's the phone? I didn't see a hunting, right? Well, let's ask the assistant. Let's go back over to the assistant and let's let the assistant show the hat contents. Voila, there's the hunting. Snuck that in while nobody was looking. So I'm gonna let Peter talk about the more interesting part of things. So, oh, and I should mention though, for anybody, the codes on maglev, I've codes on maglev, codes on github maglev, you can clone it, you can load it with our VM, the maglev part is all MIT license. Fork it, make changes to it, send us pull requests, whatever. Please follow us on Twitter. There's a website at maglev.jimstone.com but I updated it so very early on, I think you can talk about it. And we'll let Peter talk about the more fun stuff. I want to cover a bit about free lunch but I'm gonna talk about the technical details of it. At first I just wanna run through some of the areas where maglev doesn't, free lunch is sold to us. What are some of the features between small talk and ruby that look like they really match up well? If you talk about dynamic languages, small talk's definitely a dynamic language and so is ruby. So that's a good match. What about objects? Well, small talk, everything's an object and it's the same thing with ruby. Everything's an object. What about blocks? Small talk, they have blocks all over the place. Ruby, yes. Not only do we have blocks, we have procs and lambdas as well. So that's already looking like a straight slam dunk there. Meta-programming, small talk has metaprogramming. That's how you make classes. You send messages to other classes to tell them to subclass themselves. All that stuff is really done through metaprogramming. And ruby, same thing. Meta-classes, small talk hasn't built in. Ruby, well, you got something called singletons and people call them meta-classes, so maybe that's the same thing, I don't know. So we go on. So obviously, it's gonna be a real simple case to get ruby to run right on an agla. They're virtually identical. Small talk, gemstone, and now we've been taught by VMware, but has a small talk to VM. It's fast, 64-bit, has built-in object persistence, and Monty just showed that. It's proven in the industry. A lot of finance, banks, transport. A lot of people run business-critical apps, 24x7 on the small talk VM with the object persistence. So it should be real simple for gemstone to get this thing up and running. Well, I had a professor in history who said that really the similarities are rarely as interesting as the differences. And so I'm gonna talk about some of the differences between ruby and small talk that sort of paid my lunch for the last couple of years. There is no such thing as a free lunch. So problem one, when you're trying to get rails to run, we finally got it running, but it took five minutes from the time I typed rails server to the time I got that little prompt that said, listening on port, you know, one, two, three, four. That's really not gonna fly. Once you get over your initial shot with that, you wanna ask, well, why? Why does it take so long? So poke around, do some performance analysis and everything, and what I find out is that the send sites cache is being invalidated thousands of times in booting up rails. It's actually tens of thousands of times. So that's definitely gonna be a problem. So I wanna talk a little bit about what a send site is and why you might wanna cache something in it, and then we'll talk about what we did to fix that. Well, a send site is basically wherever a message is sent. If the name comes from the fact that when you send a message, there's a byte code that's run, it's named send something with it. Send sites are where we send a message. There we're sending the message each to an array. There we're sending the message inspect to whatever is an X, and there we have a send of the message put S to the implicit top level object. Each one of those send sites corresponds to a byte code. So we have two bytes in that highlighted a little bit of code there that we're gonna look at. We have a inspect send byte code and a send self, and each of those will have a send site cache. And the thing that gets put into a send site cache is the mapping between the receiver's class and the actual method that we wanna implement. Ruby's a dynamic language, and we don't know ahead of time what actual concrete method we're gonna do, and that can change from moment to moment as you do metaprogramming and all these other things. So that's the thing that we wanna cache in there. And the reason why we wanna cache is it takes a lot of time to crawl around the inheritance hierarchy, find the right method, and then invoke it. And so we wanna cache that lookup whenever we can. So I'm gonna do a quick little run through this little bit of highlighted code and watch how the send site cache is built up. So when we start the loop, we're assuming that all the send site caches are empty, and the first time through the loop, X is a string. So we look down at the send byte code and there's nothing in the send site cache. So we have to go crawl around the hierarchy, we go look in the class, single click class, we go look in the class, look in the mixed in modules. Eventually, we find it. We find that when you have the string, the right method is the one in string. And so that's the concrete method that we put into the send site cache. So that's fine. Now we're gonna do our second put s, but do our second put a message send, which we wanna put s, and that's the implicit top-level object, which is an instance of object. And again, the send site cache is empty, so we gotta crawl around the hierarchy again and try and find the right concrete method to actually put in that send site cache. So we spend a lot of time doing that, and we finally find out that actually this one comes out of kernel, this is where put s as it's a module mixed into object. And so we can finally put that in our send site cache and go off and execute the method. Now we're going the second time to the loop and x is a symbol this time. So we go to our first send by code, and again, we have something in the send site cache, but it's not the right thing. We have the receiver, this time is a symbol, not a string, so we have to go crawl around the hierarchy, find out the right method, and turns out it's symbol has its own version of inspect, and we put that in there and then we invoke that and go on. So now we're going to try and implement to the same for put s, it's the same object, and we've already got, so we get a send site cache hit this time. We already have the mapping from object to the actual concrete method that we're gonna be invoking, and so we can directly call that method and we save all that, but we don't have to go crawling around the hierarchy. So then the third time to that loop, cache is all warmed up and we just go flying through, we don't have to do any crawling around, looking for methods. So the question is, what invalidates a cache? Why would Rails be doing that would keep along our send site caches? Well, anything that messes with the hierarchy and that would change what method we would find if we get to look up again. So if you define a new method, that method might get inserted somewhere in the hierarchy and if you start the method, look up again from the receiver's class all the way out. We might find that new method and so that might be something that can invalidate a send site cache. Removing the method likewise, we might have a method that's cached and we can, if you remove a method, that could, we might be actually calling a method that no longer exists in system. So that's something else. We're aliasing a method, very similar to defining a new one. You can redefine a method. The actual class that you find the method in may not change, but the contents of that method, it's a brand new method, even though it's named the same and it's in the same class, that cell also can blow a cache. And any change in the hierarchy, you start mixing in new modules or whatever and that could also change the type of method. So what was Rails doing when it was coming up and taking five minutes, five minutes for it to load? Well, basically it was writing code and I did a quick little count and there were at least 227 defined methods. There was 182 alias methods, 520 after readers, after writers and there was a lot of other stuff that it was doing. So Rails is writing a lot of code and mucking with the hierarchy a lot when it comes up and that was really blowing our send side caches. But that's still not the whole story because it took five minutes for Maglev but other VMs have send side caches but they boot Rails much quicker than five minutes. So there's still something else going on in the system that I didn't quite understand. Why would we invite that one? So the problem is Maglev was doing explicit invalidation of the caches. What does that mean? Well, it means basically, this is pseudo code, but for every method in the entire system, then for every send side in that method, lovingly scrape it clean, paint it new and go on to the next one. So we were spending all of our time in this kind of brain dead stupid loop. So what was our solution? I'm gonna go through the solution kind of quickly because it's not really the interesting part of this thing. We decided to go with lazy invalidation of send side caches. We don't need to blow every single one at every single time explicitly. What that involves is the VM now has a serial number, call it the serial number and each send side cache gets its own serial number as well. If the serial number and the send side cache matches the VM serial number, the cache is good and we can use the contents of that cache. If however, like in the put S1, the send side serial number, 873, is different than the VM serial number, then we know that that particular cache is invalidated and we'll have to, well, we'll clean it out at the point we run that and update it with new information. To invalidate a send side cache, all we have to do is increment the number. It's pretty simple operation. But what that does is when we come to the next time and do a send inspect, we take a look at its send side cache and it's invalid now, 1234 is not equal to 1235. And so that cache is invalidated, we blow it and we have to go refill it all up again. And likewise with that, that's all right. In addition to just having send side caches themselves maintain a serial number, the real effort is in the method lookup. So we also have what's called a method lookup cache because we can cache the results of looking for mapping string class maps to this particular method that can be used by several send sites throughout the system. Because each time you send two S or one to a string, you can make use of that method lookup cache. So we have another layer of caching called method lookup cache. And we also maintain a list of recently changed method names and selectors so that we know that if the only methods that have been mucked with recently are two S and inspect, both recalling hash or any other method, we don't really, even though send side cache is invalid by serial number check, we know that we haven't changed that name so we're okay without that. So we have basically three layers of caching and they all get blown at different levels and it works a lot better. So with that solution, Rails now loads in under 15 seconds and you can get faster than that with the one page cache. That was one problem we had. But I still haven't gotten to the really interesting question I think with this particular example. And that was, why was the old code, the explicit CS101-ish iterate through everything explicitly, why was that answer acceptable to the small talkers? We obviously saw it as a huge impact in trying to load Rails. Well, the answer is because it's probably the right trade-off if you're running small talk. And why is that? Well, the way small talk approaches programming, they simply didn't run into this problem. Small talk was like the language of, or maybe I was self, I get confused. They actually, they developed the send side caches for so they weren't concerned about performance but their use of the gemstone VM was such that explicitly invalidating the caches was not a big problem. And why is that? Well, one thing is in small talk they prefer metadata to metaprogramming. So you're not gonna see a go, like the best known, I guess, small talk ORM is something called LORP. They don't do metaprogramming, they create metadata. They have a set of standard classes that represent fields and tables and rows and all that sort of stuff. But when they examine your particular database schema, they create a bunch of instances of the object to reflect that structure. So it's done in metadata and not in writing new code. But even when they do do metaprogramming, it's only done typically once or maybe once per migration because they have the ability to save the results of that metaprogramming in the image. So if they do do metaprogramming, it's done in some developers at a particular time like Tuesday afternoon, that developers send side caches were blown but once that guy paid his cost, nobody else has to pay that cost because that code, all those changes are saved in the image and are ready for any of them that fires up will automatically get all that stuff without having to blow the send side caches. So it's a difference in culture and approaches and the tools that allow them to do that. Whereas if you look at the Ruby side of thing, Ruby, this I'm making, I don't know, maybe too bold of a statement here, but Ruby frameworks tend to prefer metaprogramming to metadata. That doesn't mean there's no metadata. People throw out YAML files here and there and there's config files and all that. But there's a lot of more emphasis on the metaprogramming than on, let's say, doing things through metadata. And furthermore, that metaprogramming happens every time any VM boots, every time on your Rails VMs boots, you load up Ruby, you run through Rails, you do all that configuring of object and hash and everything else that they do. That happens every single time you boot. Whereas in the small talk thing, it doesn't. And of course if you use Maglib, you also have the option of persisting all that stuff that changed and not having to enter the runtime costs. So the factors where that small talk can save, image can save objects and Ruby literally just has the fewer options. I'm gonna skip over the RE1 and go to problem two. So another problem we knew, that the first problem we talked about was something kind of blindsided us. We weren't expecting that but we were starting to implement Maglib. This other, the second problem I'm gonna talk about is one where we actually did know about before we started Maglib. And that's a variable number of arguments. In small talk, which the VM was originally designed for, there's a fixed number of parameters per method and that never changes. Ruby on the other hand has optional parameters, it has flat odds, you know, there's that implicit block that may or may not be passed into a method. And so those are, so Ruby has this issue of how do you communicate the number of parameters that a call side is actually passing to a method and we have to have some sort of protocol for matching those two things up. In small talk, it's encoded in the method name. It's either syntactically impossible to send the wrong number of arguments or you're gonna get a message not understood error. So here's a bit of small talk. Student favorite color is a hash and small talk is called dictionary. The name of this method that we're sending is at colon put colon. And then the arguments go right after the keywords there. So we're putting into the hash, we're putting the entry to fred lights red. You can't pass the incorrect number of arguments there. You can try not to pass something but the compiler won't let you get past that, that's a syntax error. So you can't compile that method. If you try and add, it's making an extra argument, well number one you have to come up with a new keyword for that. And then hash doesn't have, dictionary doesn't have a method called at colon, put colon, no colon. So that's gonna be method not understood so there's no danger there. You can try attaching something to the end of the message but that's legal syntax and what will happen is the at colon put will be call and the result of that call will be the VML time sending the message xxx to that and you will find message xxx in the blue object. So you basically can't really send the wrong number of arguments. In Ruby of course it's not encoded in the name and it's really easy. You have a depth method a, it's easy to get a mismatch. That will work fine, we're passing, it's defined with one argument, we're passing one argument. That's a method with no parameters, that's syntactically correct. We're gonna find the right method but we're gonna get an argument error there. Likewise, if we send a ton of arguments we're also gonna get an argument error. So what do we do about it? Well it's, we have to, well to understand the solution we're gonna take a quick look at the actual stack frames and how things get sent. So briefly from this code, this is a stack frame when we're calling from a method into another one. Below the bottom third of that is set up by the calling code when you, before transfer of controls done. That middle part is overbooking that's set up by the send by code in the top part is where the target method takes over. So a simple example we have a method m that simply returns whatever you pass it in and then down below that we have an invocation of that method. At the call site when we invoke that method what we're gonna do is the first thing we're gonna do is we're gonna push the receiver of the object onto the stack. So that goes on the bottom of the stack. In our case it's, that's just not m. That's a typo. It's gonna be the top level object. The next thing we're gonna push is the one argument we're gonna send and since we're sending 10 that gets pushed onto the stack. So at this point we have, below the line is set up before we do the send call. The send byte code is basically gonna keep track, push the instruction pointer that we're gonna return to. It's gonna push the saved frame pointer so we can get back to the previous back frame. It's gonna push, then it's gonna actually look up and actually find the method using all the send site caches and everything that we talked about earlier. And then it's going to push that code pointer onto the top of the stack. At this point we're ready to transfer control to the calling method. So here's the bottom that'll receive the stack as the calling method is gonna receive it. And in this example I'm gonna say that the caller and the call agree on the number of parameters. So that what the compiler emits when it's compiling this that MA method is it already knows the offsets in the stack frame for where all the arguments are passed. We always know that the last parameter that's passed is gonna be at the frame pointer plus 16. So that offset is already calculated at compile time and put into the method. And likewise the offset to the receiver on the stack is also calculated at compile time and that offset is put directly into the method. So we have all those things pre-calculated. There's no real protocol within the stack. We don't push like the number of hours we're passing or anything like that. If the caller and target disagree on the number, for instance, we have a definition where we have an optional parameter. So it's legal to call M10. Well, if you take a look at the frame pointer plus 16 you go down and look at our actual frame. We have where it thinks B is the calling method, the target method thinks that the argument B should be the frame pointer plus 16. Well the calling method shoved A, the parameter A there. So we're already in trouble there. And likewise the called target method thinks that the argument A should be a frame pointer plus 24. But that's where the receiver was pushed in our actual frame there at the bottom. And then when we look at the receiver we don't know what we're gonna get because it's gonna be whatever happened to be at the top of the stack when things happen. So that's kind of the issue we had. Small talk never ran into this problem because there was never any disagreement between what you're calling and what you ended up with. But we had to come up with something for Ruby. So the solution we did, we wanted to not really mess with the VM internals and muck with all that code. We also didn't want to really impose a runtime cost on small talk because they already had a really efficient implicit protocol. So we decided to leverage the small talk naming convention and we came up with this idea of rich methods. Evolved no VM changes. So how does that work? Well compile time, here we have a method with fixed parameter and optional parameter. And that actually compiles to 16 methods. Notice they're named kind of weird. So what we do is we actually make these methods, these are called bridge methods. The colons denote a parameter. Stard, the nodes that were passing the splatards and ampersand nodes that were passing the block there. You notice that one purple one over there was m colon colon. That's the actual real method that we're compiling because our current method here has two parameters. So that's where we're gonna actually put the real code. So what's in all of these other things? Well those are called, those are bridge methods and we'll take a quick look at what's happening. So that's our method. Suppose we're gonna send something that matches up. We're gonna send, we've defined a method that takes two parameters and we're passing two parameters. What we're actually gonna do is we're gonna do a send of m colon colon, which we're gonna line up to that real method that we compiled and we just go straight in, all the arguments will line up and we execute code. What if we only pass one? And this method is allowed to pass one and we should have an implicit b equals 10. So we're gonna send them, at the call site, we're gonna be sending the message m colon denoting a one-art thing. And that method is implemented as a bridge method that simply allocates the proper amount of space on the stack and then goes ahead and calls the real method, m colon colon. And so what happens when we call with an incorrect number of arguments, for instance we call it no arguments, that's gonna be a send of m and that when we look up m, we're gonna find a bridge method that basically raises an argument error. So that's basically how we dealt with that issue there. We could have done something else by passing number args to the stack or the number of other ways we could have approached that, but this had the virtue of lining up well with a small talk, not imposing a runtime cost on small talk and still dealing with all the things. Plus we had a nice way of dealing with implicit blocks and then splat args. There are a lot of other things we overcame too, I don't have time to go into any details on. For instance, Ruby and small talk coexist. Inside the VM there are different, what are called environments. So we can have a set of small talk, small talk doesn't even know about Ruby. You can, there's a little bit of implicit syntax if you want to call it into Ruby, but all the small talk classes and hierarchies and methods, they're all in this pristine environment over here. We have a whole nother environment that we have the Ruby code in and that allows us to mess with the inheritance hierarchy we need to. We can override methods and not mess up with the small talk things and small talk can run well and we can call over on to the small talk side if we need to. There are dynamic instance variables in Ruby. Ruby allows you to, in a small talk, the class defines the set of instance variables every single object carries with it and we can pre calculate those and load those up front. But in Ruby, instance variables are allocated and come into existence dynamically as an side effect of running methods. So we added, we have a little bit of a runtime cost on that, but we were able to implement that. We've gone through three parsers. So we started off with the MRI parser then we went off with Ryan Davis's Ruby parser. There's a pure Ruby parser that was a little slow and now we're on to a C-based parser. There's some issues with blocks and lambdas because the one concept in Ruby has three. We added a few byte codes and there was a whole, the Singleton class is looking like meta class, it's like it's down the wrong path for a while. But anyway, that's about all the time I have for that. So I think I will open up for any questions. On the bridge method, can you go back a couple slides? Which slide you want? The one that had the six names. The implementation of the three bridge methods. Oh, the three bridge methods. Yeah. We're back before. This one. So the middle one, I guess you're putting them in the single argument case, you're pushing nil, right? So the question is, what are we pushing for that same argument? What happens, we simply need to allocate the space because that the default parameter B equals 10, that check for nil in that spot is done by the preamble to the target method. It may differ depending on what method you actually get. Yes, yeah. So that checks for that and then says, oh yeah, it is a nil. It's our secret marker value. And then the preamble there will put in value 10 and move on. Your call site caches, you're actually using Ruby caches for that? No, I was just using that as a example. It seems like, it's like the old small talk association objects there, too, to get some aliasing on that and get some, you know. Well, we're not even using small talk things. Well, I mean that kind of idea. Oh yeah. Yeah. It's done in C inside the VM. Yeah. So do you create the separate bridge methods for every Ruby method or is it only if there is an optional? No, we have to create them even if there's a fixed thing because you can still invoke the method with any number of arguments you want. And we only go up to three colons and then at that point we fill our hands, you stuff everything in an array and on the other side we can pass that array so you can pass as many arguments as you want. Any other questions? Okay. Thanks guys. Thank you.