From ed0d766705486b6cde10f7400040cf1549ab5c34 Mon Sep 17 00:00:00 2001 From: Torsten Ruger Date: Sun, 15 Apr 2018 15:24:29 +0300 Subject: [PATCH] add a page on calling convention --- app/assets/stylesheets/hacker.sass | 3 +- app/views/pages/rubyx/_menu.haml | 1 + app/views/pages/rubyx/calling.html.haml | 116 ++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 2 deletions(-) create mode 100644 app/views/pages/rubyx/calling.html.haml diff --git a/app/assets/stylesheets/hacker.sass b/app/assets/stylesheets/hacker.sass index d2a698c..a50fd3f 100644 --- a/app/assets/stylesheets/hacker.sass +++ b/app/assets/stylesheets/hacker.sass @@ -14,7 +14,7 @@ body background: $body-background url("bkg.png") 0 0 color: $body-foreground font-size: 16px - line-height: 1.5 + line-height: 1.4 font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace @@ -46,7 +46,6 @@ header margin: 0 0 40px 0 h1 font-size: 30px - line-height: 1.5 margin: 0 0 0 -40px font-weight: bold font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace diff --git a/app/views/pages/rubyx/_menu.haml b/app/views/pages/rubyx/_menu.haml index acc4a63..70614a3 100644 --- a/app/views/pages/rubyx/_menu.haml +++ b/app/views/pages/rubyx/_menu.haml @@ -4,3 +4,4 @@ %li= link_to "Parfait", "parfait.html" %li= link_to "Debugger", "debugger.html" %li= link_to "Memory" , "memory.html" + %li= link_to "Calling" , "calling.html" diff --git a/app/views/pages/rubyx/calling.html.haml b/app/views/pages/rubyx/calling.html.haml new file mode 100644 index 0000000..9f3a3b3 --- /dev/null +++ b/app/views/pages/rubyx/calling.html.haml @@ -0,0 +1,116 @@ += render "pages/rubyx/menu" + +%h1=title "Calling convention and method resolution" + +%p + Dynamic object oriented languages rely very heavily on dynamic method + resolution and calling. Dynamic method resolution is the process of finding a + method to call, and the calling convention defines how arguments are transferred and + control changes and returns. + +%h2 Calling +%p + To start with the "easier" problem, we'd define the calling convention first, + and note that the process is very very similar when done dynamically at run-time. + +%h3 Previous approaches +%p + A quick review of existing c-like, stack based conventions, will reveal what we + need to consider and solve. Coming from assembler, C uses a stack pointer to + push both return address and arguments. Subsequently the function may use the + the same stack to push/pop local variables, and off course it usually does calls + itself. +%p + Without going into detail, there are clear problems with this. For me the biggest + is that this is not object oriented. The size of argument and frame (local) + sizes of the stack are not locally known and require extensive knowledge of the + compiler to extract at compile time. +%p + The approach used a constant of the time: that a method returns to where it was called. + In the face of lambdas this is not true anymore. This is linked in with the + lifetime of variables that arises from having code live after the calling function has + returned. + +%h3 Linked List +%p + To overcome some of the issues, and in general create an object oriented solution, + a linked list approach was chosen over the traditional stack based. + %br + In rubyx the class that represents the elements of the linked list is called + Message. In fact the linked list is doubly linked and holds several + other necessary data, like return address, return value and others. + + The arguments and local variables are separated out as separate objects. + These instances are fully typed and as such the runtime information about the + argument is easily retrievable. + +%h2 Arguments and Locals +%p + To detail the handling of arguments and locals we'll demonstrate the approach + with the arguments and not that locals are very very similar. +%p + The Arguments are passed in what is basically a normal object. Currently + derived from NamedList, but this does not add much over basic object functionality. +%p + Argument names, as defined in the method, map to instance variable names on the + object. This approach is logically equivalent to dynamically creating a class + for each methods arguments, but we only create the Type. The Type being a mapping + of names to indexes of where the variables are stored in the object. +%p + To have the information available at run-time the object-type of the Arguments + instance has to be changed dynamically in the method setup. As the type is known + in in fact stored in the Method, this is quite easy. + +%h3 Allocation +%p + When allocating the objects needed, ie Message, Arguments and Locals, we pay some + run-time price for this more explicit handling of information. + %br + But it is not as much as one might think. All the objects are of identical size + and can be kept in a linked list. "Allocation" is then just grabbing the first link + from a known (compile-time known) place and relinking. About 20 risc instructions + in total. + %br + Also we need to update the type information in the objects as stated above, but this + too is not much. (older) Test have shown that the calling convention is about 30-50% + slower than C. This makes it very much faster than Interpretation, even taken into + account the since added functionality. I would guess by now it is about 2x slower than + c, which is very acceptable, given that it buys us many a simplification regarding + lambdas, exceptions and fibers. + +%h3 Control +%p + Transferring control is then quite simple, basically we jump to the next methods + binary address. Before the actual jump, we have to + %ul + %li Store the return address + %li Swap the current Message with the next one that we prepared + %br + This is quite equivalent to using the stack, and amounts to only one or two + instructions more. +%p + Returning from a Method is equally simple. The convention is that any possible + return value will have been stored in the current Message before the + ReturnSequence is initiated. Then we: + %ul + %li Move the return address from the message to a register. + %li Swap the previous message in (replacing the current) + %li Jump to the stored address + +%h3 Summary +%p + To summarise, we + %ul + %li use typed objects to store information + %li use a linked list + %li are well prepared for the future, lambdas etc + %li can easily implement fibres + %li do not have stack as a separate memory area, or concern + %li have performance closer to c than mri + + And maybe most importantly we have a relatively easy to understand mechanism that + as such can be reviewed and improved by many. + %br + Which may in turn lead to an elaborate inlining scheme, thus eliminating the small + performance hit completely. +