See #4 (comment)
This looks interesting: http://msdn.microsoft.com/en-us/magazine/cc163910.aspx#S2
Can the CLR buffer be pinned for the lifetime of the node.js Buffer instance created around it? That is, can the CLR buffer only be unpinned when the node.js Buffer is garbage collected? Does the JS Buffer assume it owns the memory? Can CLR byte be garbage collected while the underlying memory is pinned? To be or not to be?
I'd look at it the other way around. Allocate a chunk of native memory and provide it to the CLR as the pointer to the managed byte array. You can then also share the same native memory with a nodeJs Buffer instance.
Regarding GC and pinning, the entire idea behind pinning is that the GC no longer touches that memory. There is a design reason behind why the fixed statement is infact a control flow statement and not just a keyword, it guarantees that the code will ALWAYS leave the block and that the memory will ALWAYS be unpinned and that the GC will be able to touch it again. Whilst the managed reference is "pinned" the GC won't touch that memory, it won't reallocate it, it won't deallocate it, it won't move it. It acts as if it is a pointer to native memory (which it really is in fact). I don't think it would be wise to maintain a pinned pointer (if its even possible) due to the fact that they went to great lengths to make sure pinned references were always used inside a scope that would always be "left".
I would be looking at the internal code behind GCHandle.Alloc as it provides almost exactly what you want to do.
See ves_icall_System_GCHandle_GetTargetHandle and mono_gchandle_new
A few more interesting things: pin_ptr<>.
pin_ptr will allow you to pass a native pointer into a CLR environment without the CLR GC messing with the pointer. This is what you want I think. So long as the pin_ptr is in scope in the CLR context, then it will still remain "pinned" as far as the GC is concerned
Example from Mono:
using namespace System;
using namespace System::Runtime::InteropServices;
void WriteStringManaged (const wchar_t* str)
Console::WriteLine (Marshal::PtrToStringUni ((IntPtr) (void*) str));
int main (array<System::String^> ^args)
Console::WriteLine (L"Pure MSVCRT console application");
pin_ptr<const wchar_t> str = PtrToStringChars (L"WriteStringManaged");