text: // Copyright 2012 the V8 project authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  // This module contains the platform-specific code. This make the rest of the
  // code less dependent on operating system, compilers and runtime libraries.
  // This module does specifically not deal with differences between different
  // processor architecture.
  // The platform classes have the same definition for all platforms. The
  // implementation for a particular platform is put in platform_<os>.cc.
  // The build system then uses the implementation for the target platform.
  //
  // This design has been chosen because it is simple and fast. Alternatively,
  // the platform dependent classes could have been implemented using abstract
  // superclasses with virtual methods and having specializations for each
  // platform. This design was rejected because it was more complicated and
  // slower. It would require factory methods for selecting the right
  // implementation and the overhead of virtual methods for performance
  // sensitive like mutex locking/unlocking.
  
  #ifndef V8_BASE_PLATFORM_PLATFORM_H_
  #define V8_BASE_PLATFORM_PLATFORM_H_
  
  #include <cstdarg>
  #include <string>
  #include <vector>
  
  #include "src/base/base-export.h"
  #include "src/base/build_config.h"
  #include "src/base/compiler-specific.h"
  #include "src/base/platform/mutex.h"
  #include "src/base/platform/semaphore.h"
  
  #if V8_OS_QNX
  #include "src/base/qnx-math.h"
  #endif
  
  namespace v8 {
  
  namespace base {
  
  // ----------------------------------------------------------------------------
  // Fast TLS support
  
  #ifndef V8_NO_FAST_TLS
  
  #if V8_CC_MSVC && V8_HOST_ARCH_IA32
  
  #define V8_FAST_TLS_SUPPORTED 1
  
  INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
  
  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;
      const intptr_t kPointerSize = sizeof(void*);
      DCHECK(0 <= index && index < kMaxSlots);
      USE(kMaxSlots);
      if (index < kMaxInlineSlots) {
          return static_cast<intptr_t>(__readfsdword(kTibInlineTlsOffset +
                                       kPointerSize * index));
      }
      intptr_t extra = static_cast<intptr_t>(__readfsdword(kTibExtraTlsOffset));
      DCHECK_NE(extra, 0);
      return *reinterpret_cast<intptr_t*>(extra +
                                          kPointerSize * (index - kMaxInlineSlots));
  }
  
  #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64)
  
  #define V8_FAST_TLS_SUPPORTED 1
  
  extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset;
  
  INLINE(intptr_t InternalGetExistingThreadLocal(intptr_t index));
  
  inline intptr_t InternalGetExistingThreadLocal(intptr_t index) {
      intptr_t result;
  #if V8_HOST_ARCH_IA32
      asm("movl %%gs:(%1,%2,4), %0;"
          :"=r"(result)  // Output must be a writable register.
          :"r"(kMacTlsBaseOffset), "r"(index));
  #else
      asm("movq %%gs:(%1,%2,8), %0;"
          :"=r"(result)
          :"r"(kMacTlsBaseOffset), "r"(index));
  #endif
      return result;
  }
  
  #endif
  
  #endif  // V8_NO_FAST_TLS
  
  class PageAllocator;
  class TimezoneCache;
  
  // ----------------------------------------------------------------------------
  // OS
  //
  // This class has static methods for the different platform specific
  // functions. Add methods here to cope with differences between the
  // supported platforms.
  
  class V8_BASE_EXPORT OS {
      public:
          // Initialize the OS class.
          // - hard_abort: If true, OS::Abort() will crash instead of aborting.
          // - gc_fake_mmap: Name of the file for fake gc mmap used in ll_prof.
          static void Initialize(bool hard_abort, const char* const gc_fake_mmap);
  
          // Returns the accumulated user time for thread. This routine
          // can be used for profiling. The implementation should
          // strive for high-precision timer resolution, preferable
          // micro-second resolution.
          static int GetUserTime(uint32_t* secs,  uint32_t* usecs);
  
          // Returns current time as the number of milliseconds since
          // 00:00:00 UTC, January 1, 1970.
          static double TimeCurrentMillis();
  
          static TimezoneCache* CreateTimezoneCache();
  
          // Returns last OS error.
          static int GetLastError();
  
          static FILE* FOpen(const char* path, const char* mode);
          static bool Remove(const char* path);
  
          static char DirectorySeparator();
          static bool isDirectorySeparator(const char ch);
  
          // Opens a temporary file, the file is auto removed on close.
          static FILE* OpenTemporaryFile();
  
          // Log file open mode is platform-dependent due to line ends issues.
          static const char* const LogFileOpenMode;
  
          // Print output to console. This is mostly used for debugging output.
          // On platforms that has standard terminal output, the output
          // should go to stdout.
          static PRINTF_FORMAT(1, 2) void Print(const char* format, ...);
          static PRINTF_FORMAT(1, 0) void VPrint(const char* format, va_list args);
  
          // Print output to a file. This is mostly used for debugging output.
          static PRINTF_FORMAT(2, 3) void FPrint(FILE* out, const char* format, ...);
          static PRINTF_FORMAT(2, 0) void VFPrint(FILE* out, const char* format,
                                                  va_list args);
  
          // Print error output to console. This is mostly used for error message
          // output. On platforms that has standard terminal output, the output
          // should go to stderr.
          static PRINTF_FORMAT(1, 2) void PrintError(const char* format, ...);
          static PRINTF_FORMAT(1, 0) void VPrintError(const char* format, va_list args);
  
          // Memory permissions. These should be kept in sync with the ones in
          // v8::PageAllocator.
          enum class MemoryPermission {
              kNoAccess,
              kReadWrite,
              // TODO(hpayer): Remove this flag. Memory should never be rwx.
              kReadWriteExecute,
              kReadExecute
          };
  
          static bool HasLazyCommits();
  
          // Sleep for a specified time interval.
          static void Sleep(TimeDelta interval);
  
          // Abort the current process.
          [[noreturn]] static void Abort();
  
          // Debug break.
          static void DebugBreak();
  
          // Walk the stack.
          static const int kStackWalkError = -1;
          static const int kStackWalkMaxNameLen = 256;
          static const int kStackWalkMaxTextLen = 256;
          struct StackFrame {
              void* address;
              char text[kStackWalkMaxTextLen];
          };
  
          class V8_BASE_EXPORT MemoryMappedFile {
              public:
                  virtual ~MemoryMappedFile() {}
                  virtual void* memory() const = 0;
                  virtual size_t size() const = 0;
  
                  static MemoryMappedFile* open(const char* name);
                  static MemoryMappedFile* create(const char* name, size_t size,
                                                  void* initial);
          };
  
          // Safe formatting print. Ensures that str is always null-terminated.
          // Returns the number of chars written, or -1 if output was truncated.
          static PRINTF_FORMAT(3, 4) int SNPrintF(char* str, int length,
                                                  const char* format, ...);
          static PRINTF_FORMAT(3, 0) int VSNPrintF(char* str, int length,
                  const char* format, va_list args);
  
          static char* StrChr(char* str, int c);
          static void StrNCpy(char* dest, int length, const char* src, size_t n);
  
          // Support for the profiler.  Can do nothing, in which case ticks
          // occurring in shared libraries will not be properly accounted for.
          struct SharedLibraryAddress {
              SharedLibraryAddress(const std::string& library_path, uintptr_t start,
                                   uintptr_t end)
                  : library_path(library_path), start(start), end(end), aslr_slide(0) {}
              SharedLibraryAddress(const std::string& library_path, uintptr_t start,
                                   uintptr_t end, intptr_t aslr_slide)
                  : library_path(library_path),
                    start(start),
                    end(end),
                    aslr_slide(aslr_slide) {}
  
              std::string library_path;
              uintptr_t start;
              uintptr_t end;
              intptr_t aslr_slide;
          };
  
          static std::vector<SharedLibraryAddress> GetSharedLibraryAddresses();
  
          // Support for the profiler.  Notifies the external profiling
          // process that a code moving garbage collection starts.  Can do
          // nothing, in which case the code objects must not move (e.g., by
          // using --never-compact) if accurate profiling is desired.
          static void SignalCodeMovingGC();
  
          // Support runtime detection of whether the hard float option of the
          // EABI is used.
          static bool ArmUsingHardFloat();
  
          // Returns the activation frame alignment constraint or zero if
          // the platform doesn't care. Guaranteed to be a power of two.
          static int ActivationFrameAlignment();
  
          static int GetCurrentProcessId();
  
          static int GetCurrentThreadId();
  
          static void ExitProcess(int exit_code);
  
      private:
          // These classes use the private memory management API below.
          friend class MemoryMappedFile;
          friend class PosixMemoryMappedFile;
          friend class v8::base::PageAllocator;
  
          static size_t AllocatePageSize();
  
          static size_t CommitPageSize();
  
          static void SetRandomMmapSeed(int64_t seed);
  
          static void* GetRandomMmapAddr();
  
          V8_WARN_UNUSED_RESULT static void* Allocate(void* address, size_t size,
                  size_t alignment,
                  MemoryPermission access);
  
          V8_WARN_UNUSED_RESULT static bool Free(void* address, const size_t size);
  
          V8_WARN_UNUSED_RESULT static bool Release(void* address, size_t size);
  
          V8_WARN_UNUSED_RESULT static bool SetPermissions(void* address, size_t size,
                  MemoryPermission access);
  
          static const int msPerSecond = 1000;
  
  #if V8_OS_POSIX
          static const char* GetGCFakeMMapFile();
  #endif
  
          DISALLOW_IMPLICIT_CONSTRUCTORS(OS);
  };
  
  #if (defined(_WIN32) || defined(_WIN64))
  V8_BASE_EXPORT void EnsureConsoleOutputWin32();
  #endif  // (defined(_WIN32) || defined(_WIN64))
  
  inline void EnsureConsoleOutput() {
  #if (defined(_WIN32) || defined(_WIN64))
      // Windows requires extra calls to send assert output to the console
      // rather than a dialog box.
      EnsureConsoleOutputWin32();
  #endif  // (defined(_WIN32) || defined(_WIN64))
  }
  
  // ----------------------------------------------------------------------------
  // Thread
  //
  // Thread objects are used for creating and running threads. When the start()
  // method is called the new thread starts running the run() method in the new
  // thread. The Thread object should not be deallocated before the thread has
  // terminated.
  
  class V8_BASE_EXPORT Thread {
      public:
          // Opaque data type for thread-local storage keys.
          typedef int32_t LocalStorageKey;
  
          class Options {
              public:
                  Options() : name_("v8:<unknown>"), stack_size_(0) {}
                  explicit Options(const char* name, int stack_size = 0)
                      : name_(name), stack_size_(stack_size) {}
  
                  const char* name() const {
                      return name_;
                  }
                  int stack_size() const {
                      return stack_size_;
                  }
  
              private:
                  const char* name_;
                  int stack_size_;
          };
  
          // Create new thread.
          explicit Thread(const Options& options);
          virtual ~Thread();
  
          // Start new thread by calling the Run() method on the new thread.
          void Start();
  
          // Start new thread and wait until Run() method is called on the new thread.
          void StartSynchronously() {
              start_semaphore_ = new Semaphore(0);
              Start();
              start_semaphore_->Wait();
              delete start_semaphore_;
              start_semaphore_ = nullptr;
          }
  
          // Wait until thread terminates.
          void Join();
  
          inline const char* name() const {
              return name_;
          }
  
          // Abstract method for run handler.
          virtual void Run() = 0;
  
          // Thread-local storage.
          static LocalStorageKey CreateThreadLocalKey();
          static void DeleteThreadLocalKey(LocalStorageKey key);
          static void* GetThreadLocal(LocalStorageKey key);
          static int GetThreadLocalInt(LocalStorageKey key) {
              return static_cast<int>(reinterpret_cast<intptr_t>(GetThreadLocal(key)));
          }
          static void SetThreadLocal(LocalStorageKey key, void* value);
          static void SetThreadLocalInt(LocalStorageKey key, int value) {
              SetThreadLocal(key, reinterpret_cast<void*>(static_cast<intptr_t>(value)));
          }
          static bool HasThreadLocal(LocalStorageKey key) {
              return GetThreadLocal(key) != nullptr;
          }
  
  #ifdef V8_FAST_TLS_SUPPORTED
          static inline void* GetExistingThreadLocal(LocalStorageKey key) {
              void* result = reinterpret_cast<void*>(
                                 InternalGetExistingThreadLocal(static_cast<intptr_t>(key)));
              DCHECK(result == GetThreadLocal(key));
              return result;
          }
  #else
          static inline void* GetExistingThreadLocal(LocalStorageKey key) {
              return GetThreadLocal(key);
          }
  #endif
  
          // The thread name length is limited to 16 based on Linux's implementation of
          // prctl().
          static const int kMaxThreadNameLength = 16;
  
          class PlatformData;
          PlatformData* data() {
              return data_;
          }
  
          void NotifyStartedAndRun() {
              if (start_semaphore_) {
                  start_semaphore_->Signal();
              }
              Run();
          }
  
      private:
          void set_name(const char* name);
  
          PlatformData* data_;
  
          char name_[kMaxThreadNameLength];
          int stack_size_;
          Semaphore* start_semaphore_;
  
          DISALLOW_COPY_AND_ASSIGN(Thread);
  };
  
  }  // namespace base
  }  // namespace v8
  
  #endif  // V8_BASE_PLATFORM_PLATFORM_H_
  