Blog Closed

This blog has moved to Github. This page will not be updated and is not open for comments. Please go to the new site for updated content.

Saturday, September 19, 2009

JIT: First Project Challenge

Darbelo merged in a branch that finally gets rid of the old JIT and PIC systems. However one vestige of the JIT system still remains: the NCI frame builder. The NCI frame builder is used to create a call frame for interacting with an arbitrary library function. As I mentioned in my earlier post on Stack Frames, to call a function that follows the standard conventions, we push the arguments onto the system stack, use the call opcode to jump to the subroutine, and then when control flow returns we extract the return value from the appropriate register.

The problem is that the C programming language doesn't offer any facilities for manually constructing a call frame. In pure C, you cannot push an arbitrary value onto the stack, perform a non-local jump to a subroutine label, specify which register a value is stored in, etc. You can accomplish some of this with inlined assembly code, but if you're playing with the stack you run the risk of corrupting your program and crashing your computer. Keep in mind that local variables to a function are typically accessed as an offset from the esp register (on x86 anyway), so pushing things onto the stack will change the value of that register, which in turn will make constant offsets from that location point to different values.

When we are talking about calling arbitrary library functions from Parrot, there are three approaches:
  1. Generate a list of function calling "thunks" from a predefined list of function signatures. You end up with hundreds of such thunks but still can't interact with some functions without adding a signature and recompiling Parrot. Also, all those hundreds of functions need to be loaded into memory when Parrot starts, creating a larger memory footprint and slower startup times.
  2. Create a function in pure assembly that takes a signature string and manually constructs a call frame. In assembly we can interact with the system stack and processor registers directly. There are two problems with this: Portability, because we would need to write a new assembly routine for each combination of platform and assembler. Also, we couldn't cache the results of the generated call frame, every call to the library function would have to manually build the frame again.
  3. Use a JIT solution. The current frame builder uses Parrot's old JIT framework to build the frame code in a block of memory, but only works on x86. A "real" solution here would use a JIT package like LLVM or libJIT to generate these frames. This has the benefit that we can cache the generated thunks. We generate them lazily when we need them and cache them for when we need them again.
Option #3 is probably what we are going to end up with, although being able to sanely fall back to Option#2 when a JIT library isn't available might be a good idea, especially for those rare platforms that aren't supported by our JIT engine.

This in mind, I have two challenges for readers who have some spare time:
  1. Create a proof-of-concept NCI frame builder using a "real" JIT engine. You can pick anything you want (libJIT, LLVM, GNU Lighting, dynASM, nanoJIT, etc). It must be able to take a function pointer, a string representing the call signature, and proper arguments and no other unnecessary state information or metadata. The frame builder should return the compiled thunk from the JIT engine that can be used to call the target function.
  2. Create a proof-of-concept NCI function caller using pure assembly or C with inline assembly. Your assembly routine should take a signature string, a function pointer, and a list of arguments, and a pointer to a memory location to hold a return value (if any).
Winning solutions don't need to be integrated into Parrot or use Parrot-style signature strings. Solutions don't need to be large or involved either, just a simple demonstration of the mechanisms needed to call arbitrary functions on your target platform. Bonus points for providing a solution that is related to what Parrot needs, and definite bonus points for targetting an uncommon platform (x86+GCC for instance is very common).

There is no real prize for "winning", but I'll post good submissions here to my blog, publically talk about how awesome you are, and maybe try to get your solution added to Parrot in some way and in some form.

2 comments:

  1. Hi!

    Congratulations! Your readers have submitted and voted for your blog at The Daily Reviewer. We compiled an exclusive list of the Top 100 Perl Blogs, and we are glad to let you know that your blog was included! You can see it at http://thedailyreviewer.com/top/perl

    You can claim your Top 100 Blogs Award here

    P.S. This is a one-time notice to let you know your blog was included in one of our Top 100 Blog categories. You might get notices if you are listed in two or more categories.

    P.P.S. If for some reason you want your blog removed from our list, just send an email to angelina@thedailyreviewer.com with the subject line "REMOVE" and the link to your blog in the body of the message.

    Cheers!

    Angelina Mizaki
    Selection Committee President
    The Daily Reviewer
    http://thedailyreviewer.com

    ReplyDelete
  2. Just a quick note to anybody else who is reading this: the award above was not for my blog, it was intended for Planet Parrot instead. The message got dropped here because this post was at the top of the listings for Planet Parrot and I don't think the Top 100 people recognized it as an aggregator.

    ReplyDelete

Note: Only a member of this blog may post a comment.