I am intrigued by how V8's scopes work.
How can a scope object on the stack find other scope objects and contexts further up the stack?
Digging into how HandleScopes worked I found that they rely on thread locals. This has left me wondering how these work in C++, I've found the implementation but still don't feel I understand what's going on.
api.cc -- HandleScope looks for the current Isolate
HandleScope::HandleScope() {
i::Isolate* isolate = i::Isolate::Current();
API_ENTRY_CHECK(isolate, "HandleScope::HandleScope");
v8::ImplementationUtilities::HandleScopeData* current =
isolate->handle_scope_data();
isolate_ = isolate;
prev_next_ = current->next;
prev_limit_ = current->limit;
is_closed_ = false;
current->level++;
}
isolate.cc -- static method looks for the current isolate as thread local
// Returns the isolate inside which the current thread is running.
INLINE(static Isolate* Current()) {
const Thread::LocalStorageKey key = isolate_key();
Isolate* isolate = reinterpret_cast<Isolate*>(
Thread::GetExistingThreadLocal(key));
if (!isolate) {
EnsureDefaultIsolate();
isolate = reinterpret_cast<Isolate*>(
Thread::GetExistingThreadLocal(key));
}
ASSERT(isolate != NULL);
return isolate;
}
platform.h -- calls a low level method to retrieve thread local
static inline void* GetExistingThreadLocal(LocalStorageKey key) {
void* result = reinterpret_cast<void*>(
InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
ASSERT(result == GetThreadLocal(key));
return result;
}
platform-tls-win32.h -- the magic happens
inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
const intptr_t kTibInlineTlsOffset = 0xE10;
const intptr_t kTibExtraTlsOffset = 0xF94;
const intptr_t kMaxInlineSlots = 64;
const intptr_t kMaxSlots = kMaxInlineSlots + 1024;
ASSERT(0 <= index && index < kMaxSlots);
if (index < kMaxInlineSlots) {
return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
kPointerSize * index));
}
intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
ASSERT(extra != 0);
return *reinterpret_cast<intptr_t*>(extra +
kPointerSize * (index - kMaxInlineSlots));
}
You can view InternalGetExistingThreadLocal
as an inline version of TlsGetValue
WinAPI call.
On Windows in user mode fs
segment register allows code to access Thread Information Block (TIB) which contains thread specific information, for example Thread Local Storage structures.
Layout of TIB and the way TLS is stored inside TIB is exposed in DDK (see http://en.wikipedia.org/wiki/Win32_Thread_Information_Block for quick overview of the TIB layout).
Given this knowledge and ability to read data from TIB via __readfsdword(offs)
(which is equivalent of reading dword ptr fs:[offs]
) one can directly and efficiently access TLS without calling TlsGetValue
.