Hey all, it's been a while since I have posted on this list, but I've been continuing my work with LLVM and getting lots done :) One question I wanted to ask is whether anyone had any advice on how to implement "perfect forwarding" in a runtime (as opposed to compile-time) context with LLVM. The general idea is that you have a bunch of methods that have different call signatures, and you want to have some generic handler function that can intercept these calls and then forward each call to another method that has the same signature as the original call. A typical example of how this would be used is something like Mockito or EasyMock - you have some interface, and you dynamically create an implementation of that interface which is able to intercept all of the method calls and record the order in which they are called and the value of the arguments. The unit test code then performs some validation on the recording to ensure that the invocations match what was expected. The key point is that the handler method doesn't know at compile-time the call signature of the various methods that are going to be intercepted. In the case of Java and C#, the VM is able to box all of the arguments that are primitive types, and pass to the handler method an array of type Object[]. Similarly, one can call method.invoke() on a method, passing in that same array of objects, and the VM will unbox the primitive types and then call the actual method with the right argument types. One obvious way to do this is to generate two stub functions for every function emitted by the compiler, one that takes the original argument signature and creates a list of boxed objects, and one that takes a list of boxed objects, unboxes them and then calls the function. However, that's a lot of extra code to generate, and I am concerned about the amount of code bloat that would create. What would be better is if there was some way for the generic handler function to be able to dynamically get a picture of the layout of the call frame. On the receiving end, this would be something similar to a varargs call, where the called function unpacks the argument list based on a runtime-provided schema. One problem with the varargs approach is that I wouldn't want every method call to have to use the varargs calling convention. On the calling side, I'm not sure that any language has a means to dynamically construct an argument list for a call. If such a thing did exist, what I suppose it would do is given a description of a function's calling signature, figure out which arguments should be put in which registers and which should be pushed on the stack. In other words, to do at runtime what LLVM currently does at compile time. -- Talin
> > What would be better is if there was some way for the generic handler > function to be able to dynamically get a picture of the layout of the > call frame. On the receiving end, this would be something similar to a > varargs call, where the called function unpacks the argument list based > on a runtime-provided schema. One problem with the varargs approach is > that I wouldn't want every method call to have to use the varargs > calling convention. > > On the calling side, I'm not sure that any language has a means to > dynamically construct an argument list for a call. If such a thing did > exist, what I suppose it would do is given a description of a function's > calling signature, figure out which arguments should be put in which > registers and which should be pushed on the stack. In other words, to do > at runtime what LLVM currently does at compile time. > > -- Talin >It so happens that I'm working on a language (and compiler for same) that does just that and more. It has built-in support for runtime code generation, as well as arbitrary compile-time code execution. Basically, all functions are compiled by having my compiler create code that issues LLVM calls to create the actual function. Thus, each "normal" function is created by having the compiler emit and then JIT and run a function whose purpose is to create the "normal" function. When it's all done, the Module is written out, and opt can clean up the mess. But if you want runtime code-generation, these function-generating-functions can actually be called at runtime, and you can pass parameters to them, and get basically everything you would get from C++ templates and more. And the "normal" function code has hooks to have its generator-function call other custom functions - those are either the usual kind of function-generating-functions, or "normal" functions in their own right with explicit LLVM calls to generate code to be incorporated into the calling function's target. I'm not sure how this could best be used in conjunction with an existing language, but I'd be happy to post as much detail as y'all are interested in. A "basic" variant of the language that handles all existing LLVM types but doesn't add class constructs, or even names for struct fields, is working fairly well as a prototype on my system, and I'm about to start writing a standard library for it and adding extensions such as overloaded operators and class descriptions with named fields & methods. As it stands, "perfect forwarding" should be well within its capabilities. (Especially since I'm not putting in C++-like "references")
Reasonably Related Threads
- [LLVMdev] Perfect forwarding?
- [LLVMdev] Perfect forwarding?
- [LLVMdev] PSA: Perfectly forwarding thunks can now be expressed in LLVM IR with musttail and varargs
- [LLVMdev] PSA: Perfectly forwarding thunks can now be expressed in LLVM IR with musttail and varargs
- [LLVMdev] Extracting all BasicBlocks of a Function into new Function