Q:

Memory layout of JavaScript objects in V8

I'm looking to writing some C bindings to V8, and so I'll need to figure out the memory layout of the various primitive JavaScript types. Is there any documentation on these details anywhere?

A:

You don't need to know data types layout to write C bindings for V8. Object's are never really accessed directly when you work with V8 but through an API - only V8 implementation knows how they are laid out. For example getting a property foo from an object o looks like this in C++:
v8::Handle<v8::Object> o;
v8::Handle<v8::Object> v =
  o->Get(v8::String::NewFromUtf8(isolate, "foo"));

Now to wrap this into C you only need to know how to represent and pass around v8::Handle<T>, then you can write wrappers like:
template<typename T> Handle<T> FromC(v8_handle_t h) { /* ... */ }
template<typename T> v8_handle_t ToC(Handle<T> h) { /* ... */ }

extern "C" v8_handle_t v8_object_get(v8_handle_t self, 
                                     v8_handle_t key) {
  return ToC(FromC<Object>(self)->Get(FromC<Value>(key)));
}

So what's inside v8::Handle<T>? In reality it's just a pointer to some slot which in turn contains an actual pointer to an underlying V8 object. This double indirection exists to enable V8 GC to precisely track which objects are in use in C++ code and to allow it moving this objects. 
So theoretically you can define v8_handle_t as an opaque pointer and marshall it like this:
typedef struct v8_object_pointer_t* v8_handle_t;  // Opaque pointer
static_assert(sizeof(v8_handle_t) == sizeof(Handle<Object>))
template<typename T> Handle<T> FromC(v8_handle_t h) {
  return *(Handle<T>*)&h;
}
template<typename T> v8_handle_t ToC(const Handle<T>& h) {
  return *(v8_handle_t*)&h;
}

A minor complication comes from managing the structure called HandleScope that manages Handles. In C++ API it relies on RAII-pattern to manage some backing storage. The simplest way to deal with it probably is:
typedef struct {
  void* a[3];
} v8_handle_scope_t;
static_assert(sizeof(v8_handle_scope_t) == sizeof(HandleScope))
void v8_handle_scope_enter(v8_handle_scope_t* scope) {
  new(scope) HandleScope; 
}
void v8_handle_scope_leave(v8_handle_scope_t* scope) {
  delete (HandleScope*)scope;
}

With carefully balanced usage in code that needs handle scopes:
for (i = 0; i < N; i++) {
  v8_handle_scope_t scope;
  v8_handle_scope_enter(&scope);
  // action
  v8_handle_scope_leave(&scope);
}

