Partially Applied Functions in C
tia.mat.br
tia.mat.br
It would need some changes to be truly architecture-independent; for example it should use memcmp() instead of this idiom which can throw SIGBUS on some platforms due to the unaligned access:
if (*((intptr_t *)code) == look) {
I used a similar hack once when I wanted to create an ELF object file at runtime, which is necessary to use the GDB JIT interface (http://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html). I didn't want to implement the whole ELF format myself, but I needed this ELF file to point to some JIT code that is located at an address that is only known at runtime. I achieved this by generating the ELF object file with gcc at build time, but used a similarly distinctive constant for the address so I could patch it up at runtime.If you wanted to do this through straight-up codegen (instead of patching) this would be really easy with DynASM, and you could use my tutorial here as a guide:
http://blog.reverberate.org/2012/12/hello-jit-world-joy-of-s...
Edit: and of course, you run the possibility that on some archs, 0XFEEDBEEF is actually a valid encoding for some instruction. :)
The list of problems is way longer, by the way. This code makes assumptions on pointer size (I don't think it will run on x64 with common ABI's)
There also is no guarantee that function pointers point to the memory where the function's code can be found (there could be a trampoline in-between, or a devious compiler writer could encrypt function addresses).
Neither is there a guarantee that functions defined sequentially get addresses that are laid out sequentially (there is no portable way to figure out the size of a function in bytes).
Finally, I don't think there is a guarantee that one can read a function's code (its memory could be marked 'execute only').
I guess those more familiar with The C standard will find more portability issues.
Like it would load a string, but only 4 bytes, it can load in one step
"It thereby comes down to circumstance, configuration, and the whims of the people who wrote your compiler as to whether you will get mov+movt or a single ldr pc,.X+data."
Yes, this sums it nicely
http://stackoverflow.com/questions/17738154/how-can-i-write-...
My basic mental model is that whenever you write to an executable page you pay a significant overhead. Basically all of the performance caveats that apply to self-modifying code would apply here; a good starting point might be http://en.wikipedia.org/wiki/Self-modifying_code
In my application the code generation is a one-time up-front cost that is easily amortized over the subsequent execution, so I haven't had a need to explore this question in more depth.
> JIT-like approaches seem to be the frontier for fast decompression schemes.
Interesting, I have been feeling lately like this might be an area where JIT-like approaches could yield a big benefit, but hadn't seen any actual work in this area. Do you have references to anyone doing any kind of work like that?
https://github.com/torvalds/linux/blob/master/arch/x86/net/b...
http://en.wikipedia.org/wiki/Trampoline_(computing)
http://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html
FFcall can be used to do simillar things: http://www.gnu.org/software/libffcall/
It has four subprojects:
* avcall - build a C argument list incrementally and call a C function on it.
* vacall - C functions called with variable arguments
* trampoline - closures as first-class C functions
* callback - closures with variable arguments as first-class C functions
[update] used outdated link to http://www.haible.de/bruno/packages-ffcall.html
On the down side, it only supports x86, X86-64 and Arm architectures.
A good example is that this happens in objective-c all the time when you get a block imp. The closure from the block is wrapped into a new trampoline so the you can use the block as any normal imp but with the closures state stored correctly.
You can actually do this really easily and in a cross platform way with libffi.
What is ingesting is if you are a secured platform, you might not be able to mark a page as executable and writable so this isn't always possible. On iOS we had to do an amazing hack with a .S file and the vm_remap call on Darwin. Libffi uses a cute technique as well.
Ah, yes. Blocks allow you to keep mutable data alive without specifically moving them to the heap; in any case, simply having them is more important than those differences. I am not sure what you mean about types being erased.
As for the type erasure, a block is pragmatically an instance of NSBlock, which is represented as "?" in the type signature and is morally equivalent to an object id. There is therefore an implicit conversion from blocks of all types to id.
Meanwhile, even in C++, there is an implicit conversion from id to blocks of any type signature. As blocks are objects and objects often need to be smuggled around, this leads to messy and non-obvious type conversions in programs that use them.
From a language design perspective, this fails to take into consideration the history of Objective-C; while object type casting in Objective-C is sloppy, selectors are supposed to fairly uniquely map to a specific type signature.
The reason this is important is that if you have a random object, you want to be able to send it an arbitrary message and not be concerned you got the type signature wrong; the worst that can happen is that the object doesn't understand.
However, blocks mix together the concept of invocation with selectors both physically (you can even send it an invoke message) and conceptually (as you can think of the call as a special selection syntax) and yet break this type guarantee.
Even worse, blocks didn't even have their type encoded at all when they were first designed, so in addition to this being awkward at compile time, it was even fundamentally impossible to catch this kind of type error at runtime.
Thankfully, they fixed that (although now blocks compiled with older compilers, which I believe Apple simply counts gcc in its entirety as these days, won't have this information), but they did not also solve any of the other type issues.
Blocks are also a bit simpler if you want to continue to mutate the same variable both inside and outside of a lambda (but then have the variable stay alive after the outer function exits).
> As for the type erasure, a block is pragmatically an instance of NSBlock, which is represented as "?" in the type signature and is morally equivalent to an object id. There is therefore an implicit conversion from blocks of all types to id.
All objects are also represented with the same character, and all function pointers are ^?. This may be unfortunate, but isn't really about blocks; in pure C, of course, they are only erased inasmuch as all types are erased.
> The reason this is important is that if you have a random object, you want to be able to send it an arbitrary message and not be concerned you got the type signature wrong; the worst that can happen is that the object doesn't understand.
How do you mean? If you have a random `id`, or possibly an object casted to the wrong object type (isn't that the equivalent scenario, since you're talking about implicit casting from id to blocks of any type signature?) and send it a message for a selector it implements but with different types, the call will go through and probably crash, same as if you cast a block to the wrong type.
I am not certain how to best correct the misconception here. Yes: if you do this, it will crash. However, as I stated, the history of this language sets us up so that this should not happen: a selector should uniquely identify a calling signature to the best of the abilities of the programmers involved (and generally it will by accident for anything but very short names).
The reality is that this is actually not just convenient but somewhat required, as the compiler has to select a specific calling convention at compile time, so if you are using an object in a situation where it is even remotely ambiguous you get a compiler diagnostic if there is any ambiguity in the libraries you are working with with respect to the selector's type signature.
Again, with blocks, this all breaks: you can't even get a warning, because the user has to cast it first to a specific calling convention, and it isn't obvious in the code, because the cast is allowed to be implicit. The chance of an overlap is high, because the conceptual selector's name is effectively nothing. Objective-C mitigates this problem elsewhere: not here.
> All objects are also represented with the same character, and all function pointers are ^?. This may be unfortunate, but isn't really about blocks; in pure C, of course, they are only erased inasmuch as all types are erased.
A) It is not relevant that the class of an object is erased, because what's important is the type of a message implementation: you don't break the type system by having an object of the wrong class, only by sending a message with the wrong calling convention. It doesn't matter at all, therefore, whether objects are all "erased": there wasn't information there to begin with.
B) It is not relevant that C function pointers have their type erased, because they aren't also objects: the whole point of objects in Objective-C is that they are dynamically typed (back to point A: their type is irrelevant), so you are expected to use them as arguments to things like withObject: and then let them implicitly cast back on the other side. Again: selectors are king.
C) It is not relevant that in pure C types are "erased" as C does not have a runtime, so I'm not even certain how one could determine the difference between the types being erased and the types not being erased. The erasure wasn't even the core problem, remember: the erasure only makes it impossible to have runtime fixes for the actual problem, which is the compile-time selector slop.
I see what you're saying... screwing up an id cast will usually not cause low-level indeterminacy (even though it might), but screwing up a block cast always will. This seems like a pretty minor issue to me, especially as blocks usually need not be passed as ids in the first place, and Objective-C is hardly a safe language in other respects (at least historically, with retain/release).
You obviously can't pass this to C code, but it's a portable and extremely efficient solution if you are working purely within a C++ code-base.
int f(int, int, int);
the curried version of f, auto f_curried = curry(f);
must be able to take multiple arguments one-at-a-time, so f_curried(x)(y)(z) == f(x, y, z)
The code at https://dpaste.de/a8g9D/ just partially applies the function to one set of arguments, which isn't enough -- you have to keep partially applying until you get them all.As a bonus, an actual implementation of curry: https://dpaste.de/qGWcq/
Though, not to state the obvious, but if you find yourself in a need a context for an atexit() callback, then you are doing something wrong. Similarly, if a library function accepts just a function pointer, then it's either a global callback, or it's a mistake in a library design.
void *global_ptr;
int callback(){
realcallback(global_ptr);
}
int main(){
global_ptr = whatever;
atexit(callback);
return 0;
}Now say you wanted to have one invocation of realcallback with one argument, and another invocation with another. Then it makes sense for realcallback to exist - but you would still need two callback functions (and two globals). And if you needed three different invocations, you'd need three, and so on. This is all easy enough to do, but not extensible in any data-driven fashion.
The hack generates a separate thunk for each value, but at runtime, so you have as many callbacks as you have context arguments, and without needing to write them by hand ahead of time.
(Fixing the calling code is a much better solution, where available. You virtually always need a context parameter, and when you don't, it's easy enough to ignore. "Solving" the problem with this sort of ugly hack is just making more work for yourself and for others.)
data_t *global;
int main() {
atexit(callback);
atexit(set_global_to_x);
atexit(callback);
atexit(set_global_to_y);
}
Since functions are called in reverse order of their installation using atexit, you end up with two calls to callback; one with global set to y and one with global set to x.It might be more useful in cases where you want to have multiple callbacks, and don't know how many at compile time. I would still try and avoid it, though.
(And aside, I would make global_ptr static. That makes it invisible from outside its compilation unit. Even more pedantic: callback should be a void function)