Как работают области видимости и локальные потоки в (V8) C ++? - PullRequest
4 голосов
/ 28 марта 2012

Я заинтригован тем, как работают области действия V8.

Как объект области в стеке может найти другие объекты области и контексты дальше по стеку?

Детально изучив, как работают HandleScopes, я обнаружил, что они используют локальные потоки. Это заставило меня задуматься, как это работает в C ++, я нашел реализацию, но все еще не чувствую, что понимаю, что происходит.

api.cc - HandleScope ищет текущий изолят

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 - статический метод ищет текущий изолятор как локальный поток

  // 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 - вызывает метод низкого уровня для извлечения локального потока

  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 - волшебство происходит

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));
}
  • Как именно работает этот последний метод?
  • Откуда он знает, где искать?
  • Какова структура стека?

1 Ответ

3 голосов
/ 28 марта 2012

Вы можете просмотреть InternalGetExistingThreadLocal как встроенную версию TlsGetValue вызова WinAPI.

В Windows в режиме пользователя. * Сегментный регистр 1005 * позволяет коду обращаться к блоку информации о потоках (TIB), который содержит информацию о потоках, например структуры локального хранилища потоков.

Макет TIB и способ хранения TLS внутри TIB представлен в DDK (см. http://en.wikipedia.org/wiki/Win32_Thread_Information_Block для быстрого обзора макета TIB).

С учетом этих знаний и уменийчитать данные из TIB через __readfsdword(offs) (что эквивалентно чтению dword ptr fs:[offs]), можно напрямую и эффективно обращаться к TLS без вызова TlsGetValue.

...