From acbb989b3e0b879ba021c1c618317bc814da9126 Mon Sep 17 00:00:00 2001 From: johnx Date: Sat, 22 Aug 2020 10:27:50 +0800 Subject: [PATCH] Introduce Starboard platform Starboard is the platform abstraction for Cobalt. This CL introduces all Cobalt changes in src/base/platform. The review was conducted mostly on: https://chromium-review.googlesource.com/c/v8/v8/+/2247918 See b/156155426 for background Tbr: mlippautz@chromium.org Change-Id: I6cd092304ba6485acd38e82aa2dc4505d7dfb0aa Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2346090 Commit-Queue: John Xu Reviewed-by: Michael Lippautz Reviewed-by: Ulan Degenbaev Cr-Commit-Position: refs/heads/master@{#69530} --- include/v8config.h | 3 + src/DEPS | 3 +- src/base/atomicops.h | 23 +- src/base/cpu.cc | 59 +++ src/base/once.cc | 4 + src/base/platform/condition-variable.cc | 32 +- src/base/platform/condition-variable.h | 6 + src/base/platform/mutex.cc | 37 +- src/base/platform/mutex.h | 12 + src/base/platform/platform-starboard.cc | 500 ++++++++++++++++++++++++ src/base/platform/platform.h | 9 + src/base/platform/semaphore.cc | 15 + src/base/platform/semaphore.h | 6 + src/base/platform/time.cc | 36 +- 14 files changed, 738 insertions(+), 7 deletions(-) create mode 100644 src/base/platform/platform-starboard.cc diff --git a/include/v8config.h b/include/v8config.h index bbd1d6ce97..ae89edb2c9 100644 --- a/include/v8config.h +++ b/include/v8config.h @@ -70,6 +70,7 @@ // V8_OS_POSIX - POSIX compatible (mostly everything except Windows) // V8_OS_QNX - QNX Neutrino // V8_OS_SOLARIS - Sun Solaris and OpenSolaris +// V8_OS_STARBOARD - Starboard (platform abstraction for Cobalt) // V8_OS_AIX - AIX // V8_OS_WIN - Microsoft Windows @@ -93,6 +94,8 @@ #elif defined(__sun) # define V8_OS_POSIX 1 # define V8_OS_SOLARIS 1 +#elif defined(STARBOARD) +# define V8_OS_STARBOARD 1 #elif defined(_AIX) #define V8_OS_POSIX 1 #define V8_OS_AIX 1 diff --git a/src/DEPS b/src/DEPS index 6b4b6661bd..fc655fbcf2 100644 --- a/src/DEPS +++ b/src/DEPS @@ -52,7 +52,8 @@ include_rules = [ "-src/libplatform", "-include/libplatform", "+builtins-generated", - "+torque-generated" + "+torque-generated", + "+starboard", ] specific_include_rules = { diff --git a/src/base/atomicops.h b/src/base/atomicops.h index 01a01c5ff4..5d6422be52 100644 --- a/src/base/atomicops.h +++ b/src/base/atomicops.h @@ -36,9 +36,25 @@ #include "src/base/base-export.h" #include "src/base/build_config.h" +#if defined(V8_OS_STARBOARD) +#include "starboard/atomic.h" + +#if SB_API_VERSION < 10 +#error Your version of Starboard must support SbAtomic8 in order to use V8. +#endif // SB_API_VERSION < 10 +#endif // V8_OS_STARBOARD + namespace v8 { namespace base { +#ifdef V8_OS_STARBOARD +using Atomic8 = SbAtomic8; +using Atomic16 = int16_t; +using Atomic32 = SbAtomic32; +#if SB_IS_64_BIT +using Atomic64 = SbAtomic64; +#endif +#else using Atomic8 = char; using Atomic16 = int16_t; using Atomic32 = int32_t; @@ -51,10 +67,15 @@ using Atomic64 = int64_t; using Atomic64 = intptr_t; #endif // defined(__ILP32__) #endif // defined(V8_HOST_ARCH_64_BIT) +#endif // V8_OS_STARBOARD // Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or // Atomic64 routines below, depending on your architecture. +#if defined(V8_OS_STARBOARD) +using AtomicWord = SbAtomicPtr; +#else using AtomicWord = intptr_t; +#endif // Atomically execute: // result = *ptr; @@ -126,7 +147,7 @@ Atomic64 Acquire_Load(volatile const Atomic64* ptr); } // namespace base } // namespace v8 -#if defined(V8_OS_WIN) +#if defined(V8_OS_WIN) || defined(V8_OS_STARBOARD) #include "src/base/atomicops_internals_std.h" #else // TODO(ulan): Switch to std version after performance regression with Wheezy diff --git a/src/base/cpu.cc b/src/base/cpu.cc index bae1afe7d1..c0e9e707aa 100644 --- a/src/base/cpu.cc +++ b/src/base/cpu.cc @@ -4,6 +4,10 @@ #include "src/base/cpu.h" +#if defined(STARBOARD) +#include "starboard/cpu_features.h" +#endif + #if V8_LIBC_MSVCRT #include // __cpuid() #endif @@ -347,6 +351,54 @@ static bool HasListItem(const char* list, const char* item) { #endif // V8_HOST_ARCH_ARM || V8_HOST_ARCH_ARM64 || // V8_HOST_ARCH_MIPS || V8_HOST_ARCH_MIPS64 +#if defined(STARBOARD) + +bool CPU::StarboardDetectCPU() { +#if (SB_API_VERSION >= 11) + SbCPUFeatures features; + if (!SbCPUFeaturesGet(&features)) { + return false; + } + architecture_ = features.arm.architecture_generation; + switch (features.architecture) { + case kSbCPUFeaturesArchitectureArm: + case kSbCPUFeaturesArchitectureArm64: + has_neon_ = features.arm.has_neon; + has_thumb2_ = features.arm.has_thumb2; + has_vfp_ = features.arm.has_vfp; + has_vfp3_ = features.arm.has_vfp3; + has_vfp3_d32_ = features.arm.has_vfp3_d32; + has_idiva_ = features.arm.has_idiva; + break; + case kSbCPUFeaturesArchitectureX86: + case kSbCPUFeaturesArchitectureX86_64: + // Following flags are mandatory for V8 + has_cmov_ = features.x86.has_cmov; + has_sse2_ = features.x86.has_sse2; + // These flags are optional + has_sse3_ = features.x86.has_sse3; + has_ssse3_ = features.x86.has_ssse3; + has_sse41_ = features.x86.has_sse41; + has_sahf_ = features.x86.has_sahf; + has_avx_ = features.x86.has_avx; + has_fma3_ = features.x86.has_fma3; + has_bmi1_ = features.x86.has_bmi1; + has_bmi2_ = features.x86.has_bmi2; + has_lzcnt_ = features.x86.has_lzcnt; + has_popcnt_ = features.x86.has_popcnt; + break; + default: + return false; + } + + return true; +#else // SB_API_VERSION >= 11 + return false; +#endif +} + +#endif + CPU::CPU() : stepping_(0), model_(0), @@ -389,6 +441,13 @@ CPU::CPU() has_non_stop_time_stamp_counter_(false), has_msa_(false) { memcpy(vendor_, "Unknown", 8); + +#if defined(STARBOARD) + if (StarboardDetectCPU()) { + return; + } +#endif + #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64 int cpu_info[4]; diff --git a/src/base/once.cc b/src/base/once.cc index dbf6500746..ad0acbaab0 100644 --- a/src/base/once.cc +++ b/src/base/once.cc @@ -6,6 +6,8 @@ #ifdef _WIN32 #include +#elif defined(V8_OS_STARBOARD) +#include "starboard/thread.h" #else #include #endif @@ -40,6 +42,8 @@ void CallOnceImpl(OnceType* once, std::function init_func) { ONCE_STATE_EXECUTING_FUNCTION) { #ifdef _WIN32 ::Sleep(0); +#elif defined(V8_OS_STARBOARD) + SbThreadYield(); #else sched_yield(); #endif diff --git a/src/base/platform/condition-variable.cc b/src/base/platform/condition-variable.cc index 5ea70835ee..04ea29181b 100644 --- a/src/base/platform/condition-variable.cc +++ b/src/base/platform/condition-variable.cc @@ -159,7 +159,37 @@ bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) { return result != 0; } -#endif // V8_OS_POSIX +#elif V8_OS_STARBOARD + +ConditionVariable::ConditionVariable() { + SbConditionVariableCreate(&native_handle_, nullptr); +} + +ConditionVariable::~ConditionVariable() { + SbConditionVariableDestroy(&native_handle_); +} + +void ConditionVariable::NotifyOne() { + SbConditionVariableSignal(&native_handle_); +} + +void ConditionVariable::NotifyAll() { + SbConditionVariableBroadcast(&native_handle_); +} + +void ConditionVariable::Wait(Mutex* mutex) { + SbConditionVariableWait(&native_handle_, &mutex->native_handle()); +} + +bool ConditionVariable::WaitFor(Mutex* mutex, const TimeDelta& rel_time) { + SbTime microseconds = static_cast(rel_time.InMicroseconds()); + SbConditionVariableResult result = SbConditionVariableWaitTimed( + &native_handle_, &mutex->native_handle(), microseconds); + DCHECK(result != kSbConditionVariableFailed); + return result == kSbConditionVariableSignaled; +} + +#endif // V8_OS_STARBOARD } // namespace base } // namespace v8 diff --git a/src/base/platform/condition-variable.h b/src/base/platform/condition-variable.h index e864f32872..8b5c7cf569 100644 --- a/src/base/platform/condition-variable.h +++ b/src/base/platform/condition-variable.h @@ -9,6 +9,10 @@ #include "src/base/lazy-instance.h" #include "src/base/platform/mutex.h" +#if V8_OS_STARBOARD +#include "starboard/common/condition_variable.h" +#endif + namespace v8 { namespace base { @@ -64,6 +68,8 @@ class V8_BASE_EXPORT ConditionVariable final { using NativeHandle = pthread_cond_t; #elif V8_OS_WIN using NativeHandle = CONDITION_VARIABLE; +#elif V8_OS_STARBOARD + using NativeHandle = SbConditionVariable; #endif NativeHandle& native_handle() { diff --git a/src/base/platform/mutex.cc b/src/base/platform/mutex.cc index 2e2f7f9320..40702f493e 100644 --- a/src/base/platform/mutex.cc +++ b/src/base/platform/mutex.cc @@ -294,7 +294,42 @@ bool SharedMutex::TryLockExclusive() { return TryAcquireSRWLockExclusive(&native_handle_); } -#endif // V8_OS_POSIX +#elif V8_OS_STARBOARD + +Mutex::Mutex() { SbMutexCreate(&native_handle_); } + +Mutex::~Mutex() { SbMutexDestroy(&native_handle_); } + +void Mutex::Lock() { SbMutexAcquire(&native_handle_); } + +void Mutex::Unlock() { SbMutexRelease(&native_handle_); } + +RecursiveMutex::RecursiveMutex() {} + +RecursiveMutex::~RecursiveMutex() {} + +void RecursiveMutex::Lock() { native_handle_.Acquire(); } + +void RecursiveMutex::Unlock() { native_handle_.Release(); } + +bool RecursiveMutex::TryLock() { return native_handle_.AcquireTry(); } + +SharedMutex::SharedMutex() = default; + +SharedMutex::~SharedMutex() = default; + +void SharedMutex::LockShared() { native_handle_.AcquireReadLock(); } + +void SharedMutex::LockExclusive() { native_handle_.AcquireWriteLock(); } + +void SharedMutex::UnlockShared() { native_handle_.ReleaseReadLock(); } + +void SharedMutex::UnlockExclusive() { native_handle_.ReleaseWriteLock(); } + +bool SharedMutex::TryLockShared() { return false; } + +bool SharedMutex::TryLockExclusive() { return false; } +#endif // V8_OS_STARBOARD } // namespace base } // namespace v8 diff --git a/src/base/platform/mutex.h b/src/base/platform/mutex.h index c3144f7ceb..7a19b2f4aa 100644 --- a/src/base/platform/mutex.h +++ b/src/base/platform/mutex.h @@ -16,6 +16,12 @@ #include // NOLINT #endif +#if V8_OS_STARBOARD +#include "starboard/common/mutex.h" +#include "starboard/common/recursive_mutex.h" +#include "starboard/common/rwlock.h" +#endif + namespace v8 { namespace base { @@ -58,6 +64,8 @@ class V8_BASE_EXPORT Mutex final { using NativeHandle = pthread_mutex_t; #elif V8_OS_WIN using NativeHandle = SRWLOCK; +#elif V8_OS_STARBOARD + using NativeHandle = SbMutex; #endif NativeHandle& native_handle() { @@ -159,6 +167,8 @@ class V8_BASE_EXPORT RecursiveMutex final { using NativeHandle = pthread_mutex_t; #elif V8_OS_WIN using NativeHandle = CRITICAL_SECTION; +#elif V8_OS_STARBOARD + using NativeHandle = starboard::RecursiveMutex; #endif NativeHandle native_handle_; @@ -247,6 +257,8 @@ class V8_BASE_EXPORT SharedMutex final { using NativeHandle = pthread_rwlock_t; #elif V8_OS_WIN using NativeHandle = SRWLOCK; +#elif V8_OS_STARBOARD + using NativeHandle = starboard::RWLock; #endif NativeHandle native_handle_; diff --git a/src/base/platform/platform-starboard.cc b/src/base/platform/platform-starboard.cc new file mode 100644 index 0000000000..643d47ad9e --- /dev/null +++ b/src/base/platform/platform-starboard.cc @@ -0,0 +1,500 @@ +// Copyright 2020 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. + +// Platform-specific code for Starboard goes here. Starboard is the platform +// abstraction layer for Cobalt, an HTML5 container used mainly by YouTube +// LivingRoom products. Starboard was ported to platforms like PlayStations, +// AndroidTV, AppleTV, Samsung smart TVs and so on. + +#include "src/base/lazy-instance.h" +#include "src/base/macros.h" +#include "src/base/platform/platform.h" +#include "src/base/platform/time.h" +#include "src/base/timezone-cache.h" +#include "src/base/utils/random-number-generator.h" +#include "starboard/common/condition_variable.h" +#include "starboard/common/log.h" +#include "starboard/common/string.h" +#include "starboard/configuration.h" +#include "starboard/configuration_constants.h" +#include "starboard/memory.h" +#include "starboard/time.h" +#include "starboard/time_zone.h" + +namespace v8 { +namespace base { + +#ifdef __arm__ +bool OS::ArmUsingHardFloat() { + // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify + // the Floating Point ABI used (PCS stands for Procedure Call Standard). + // We use these as well as a couple of other defines to statically determine + // what FP ABI used. + // GCC versions 4.4 and below don't support hard-fp. + // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or + // __ARM_PCS_VFP. + +#define GCC_VERSION \ + (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if GCC_VERSION >= 40600 && !defined(__clang__) +#if defined(__ARM_PCS_VFP) + return true; +#else + return false; +#endif + +#elif GCC_VERSION < 40500 && !defined(__clang__) + return false; + +#else +#if defined(__ARM_PCS_VFP) + return true; +#elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \ + !defined(__VFP_FP__) + return false; +#else +#error \ + "Your version of compiler does not report the FP ABI compiled for." \ + "Please report it on this issue" \ + "http://code.google.com/p/v8/issues/detail?id=2140" + +#endif +#endif +#undef GCC_VERSION +} +#endif // def __arm__ + +namespace { + +static LazyInstance::type + platform_random_number_generator = LAZY_INSTANCE_INITIALIZER; +static LazyMutex rng_mutex = LAZY_MUTEX_INITIALIZER; + +bool g_hard_abort = false; + +} // namespace + +void OS::Initialize(bool hard_abort, const char* const gc_fake_mmap) { + g_hard_abort = hard_abort; + // This is only used on Posix, we don't need to use it for anything. +} + +int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { +#if SB_API_VERSION >= 12 + if (!SbTimeIsTimeThreadNowSupported()) return -1; +#endif + +#if SB_API_VERSION >= 12 || SB_HAS(TIME_THREAD_NOW) + SbTimeMonotonic thread_now = SbTimeGetMonotonicThreadNow(); + *secs = thread_now / kSbTimeSecond; + *usecs = thread_now % kSbTimeSecond; + return 0; +#else + return -1; +#endif +} + +double OS::TimeCurrentMillis() { return Time::Now().ToJsTime(); } + +int OS::ActivationFrameAlignment() { +#if V8_TARGET_ARCH_ARM + // On EABI ARM targets this is required for fp correctness in the + // runtime system. + return 8; +#elif V8_TARGET_ARCH_MIPS + return 8; +#elif V8_TARGET_ARCH_S390 + return 8; +#else + // Otherwise we just assume 16 byte alignment, i.e.: + // - With gcc 4.4 the tree vectorization optimizer can generate code + // that requires 16 byte alignment such as movdqa on x86. + // - Mac OS X, PPC and Solaris (64-bit) activation frames must + // be 16 byte-aligned; see "Mac OS X ABI Function Call Guide" + return 16; +#endif +} + +// static +size_t OS::AllocatePageSize() { return kSbMemoryPageSize; } + +// static +size_t OS::CommitPageSize() { return kSbMemoryPageSize; } + +// static +void OS::SetRandomMmapSeed(int64_t seed) { SB_NOTIMPLEMENTED(); } + +// static +void* OS::GetRandomMmapAddr() { return nullptr; } + +void* Allocate(void* address, size_t size, OS::MemoryPermission access) { + SbMemoryMapFlags sb_flags; + switch (access) { + case OS::MemoryPermission::kNoAccess: + sb_flags = SbMemoryMapFlags(0); + break; + case OS::MemoryPermission::kReadWrite: + sb_flags = SbMemoryMapFlags(kSbMemoryMapProtectReadWrite); + break; + default: + SB_LOG(ERROR) << "The requested memory allocation access is not" + " implemented for Starboard: " + << static_cast(access); + return nullptr; + } + void* result = SbMemoryMap(size, sb_flags, "v8::Base::Allocate"); + if (result == SB_MEMORY_MAP_FAILED) { + return nullptr; + } + return result; +} + +// The following code was taken from old v8 to deal with rounding up pointers. +namespace { +// Compute the 0-relative offset of some absolute value x of type T. +// This allows conversion of Addresses and integral types into +// 0-relative int offsets. +template +constexpr inline intptr_t OffsetFrom(T x) { + return x - static_cast(0); +} + +// Compute the absolute value of type T for some 0-relative offset x. +// This allows conversion of 0-relative int offsets into Addresses and +// integral types. +template +constexpr inline T AddressFrom(intptr_t x) { + return static_cast(static_cast(0) + x); +} + +template +inline T RoundDown(T x, intptr_t m) { + // m must be a power of two. + DCHECK(m != 0 && ((m & (m - 1)) == 0)); + return AddressFrom(OffsetFrom(x) & -m); +} + +template +inline T RoundUpOld(T x, intptr_t m) { + return RoundDown(static_cast(x + m - 1), m); +} +} // namespace + +// static +void* OS::Allocate(void* address, size_t size, size_t alignment, + MemoryPermission access) { + size_t page_size = AllocatePageSize(); + DCHECK_EQ(0, size % page_size); + DCHECK_EQ(0, alignment % page_size); + address = AlignedAddress(address, alignment); + // Add the maximum misalignment so we are guaranteed an aligned base address. + size_t request_size = size + (alignment - page_size); + request_size = RoundUp(request_size, OS::AllocatePageSize()); + void* result = base::Allocate(address, request_size, access); + if (result == nullptr) return nullptr; + + // Unmap memory allocated before the aligned base address. + uint8_t* base = static_cast(result); + uint8_t* aligned_base = RoundUpOld(base, alignment); + if (aligned_base != base) { + DCHECK_LT(base, aligned_base); + size_t prefix_size = static_cast(aligned_base - base); + CHECK(Free(base, prefix_size)); + request_size -= prefix_size; + } + // Unmap memory allocated after the potentially unaligned end. + if (size != request_size) { + DCHECK_LT(size, request_size); + size_t suffix_size = request_size - size; + CHECK(Free(aligned_base + size, suffix_size)); + request_size -= suffix_size; + } + + DCHECK_EQ(size, request_size); + return static_cast(aligned_base); +} + +// static +bool OS::Free(void* address, const size_t size) { + return SbMemoryUnmap(address, size); +} + +// static +bool OS::Release(void* address, size_t size) { + return SbMemoryUnmap(address, size); +} + +// static +bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) { + SbMemoryMapFlags new_protection; + switch (access) { + case OS::MemoryPermission::kNoAccess: + new_protection = SbMemoryMapFlags(0); + break; + case OS::MemoryPermission::kRead: + new_protection = SbMemoryMapFlags(kSbMemoryMapProtectRead); + case OS::MemoryPermission::kReadWrite: + new_protection = SbMemoryMapFlags(kSbMemoryMapProtectReadWrite); + break; + case OS::MemoryPermission::kReadExecute: +#if SB_CAN(MAP_EXECUTABLE_MEMORY) + new_protection = + SbMemoryMapFlags(kSbMemoryMapProtectRead | kSbMemoryMapProtectExec); +#else + UNREACHABLE(); +#endif + break; + default: + // All other types are not supported by Starboard. + return false; + } + return SbMemoryProtect(address, size, new_protection); +} + +// static +bool OS::HasLazyCommits() { + SB_NOTIMPLEMENTED(); + return false; +} + +void OS::Sleep(TimeDelta interval) { SbThreadSleep(interval.InMicroseconds()); } + +void OS::Abort() { SbSystemBreakIntoDebugger(); } + +void OS::DebugBreak() { SbSystemBreakIntoDebugger(); } + +class StarboardMemoryMappedFile final : public OS::MemoryMappedFile { + public: + ~StarboardMemoryMappedFile() final; + void* memory() const final { + SB_NOTIMPLEMENTED(); + return nullptr; + } + size_t size() const final { + SB_NOTIMPLEMENTED(); + return 0u; + } +}; + +// static +OS::MemoryMappedFile* OS::MemoryMappedFile::open(const char* name, + FileMode mode) { + SB_NOTIMPLEMENTED(); + return nullptr; +} + +// static +OS::MemoryMappedFile* OS::MemoryMappedFile::create(const char* name, + size_t size, void* initial) { + SB_NOTIMPLEMENTED(); + return nullptr; +} + +StarboardMemoryMappedFile::~StarboardMemoryMappedFile() { SB_NOTIMPLEMENTED(); } + +int OS::GetCurrentProcessId() { + SB_NOTIMPLEMENTED(); + return 0; +} + +int OS::GetCurrentThreadId() { return SbThreadGetId(); } + +int OS::GetLastError() { return SbSystemGetLastError(); } + +// ---------------------------------------------------------------------------- +// POSIX stdio support. +// + +FILE* OS::FOpen(const char* path, const char* mode) { + SB_NOTIMPLEMENTED(); + return nullptr; +} + +bool OS::Remove(const char* path) { + SB_NOTIMPLEMENTED(); + return false; +} + +char OS::DirectorySeparator() { return kSbFileSepChar; } + +bool OS::isDirectorySeparator(const char ch) { + return ch == DirectorySeparator(); +} + +FILE* OS::OpenTemporaryFile() { + SB_NOTIMPLEMENTED(); + return nullptr; +} + +const char* const OS::LogFileOpenMode = "\0"; + +void OS::Print(const char* format, ...) { + va_list args; + va_start(args, format); + VPrint(format, args); + va_end(args); +} + +void OS::VPrint(const char* format, va_list args) { + SbLogRawFormat(format, args); +} + +void OS::FPrint(FILE* out, const char* format, ...) { + va_list args; + va_start(args, format); + VPrintError(format, args); + va_end(args); +} + +void OS::VFPrint(FILE* out, const char* format, va_list args) { + SbLogRawFormat(format, args); +} + +void OS::PrintError(const char* format, ...) { + va_list args; + va_start(args, format); + VPrintError(format, args); + va_end(args); +} + +void OS::VPrintError(const char* format, va_list args) { + // Starboard has no concept of stderr vs stdout. + SbLogRawFormat(format, args); +} + +int OS::SNPrintF(char* str, int length, const char* format, ...) { + va_list args; + va_start(args, format); + int result = VSNPrintF(str, length, format, args); + va_end(args); + return result; +} + +int OS::VSNPrintF(char* str, int length, const char* format, va_list args) { + int n = SbStringFormat(str, length, format, args); + if (n < 0 || n >= length) { + // If the length is zero, the assignment fails. + if (length > 0) str[length - 1] = '\0'; + return -1; + } else { + return n; + } +} + +// ---------------------------------------------------------------------------- +// POSIX string support. +// + +void OS::StrNCpy(char* dest, int length, const char* src, size_t n) { + SbStringCopy(dest, src, n); +} + +// ---------------------------------------------------------------------------- +// POSIX thread support. +// + +class Thread::PlatformData { + public: + PlatformData() : thread_(kSbThreadInvalid) {} + SbThread thread_; // Thread handle for pthread. + // Synchronizes thread creation + Mutex thread_creation_mutex_; +}; + +Thread::Thread(const Options& options) + : data_(new PlatformData), + stack_size_(options.stack_size()), + start_semaphore_(nullptr) { + set_name(options.name()); +} + +Thread::~Thread() { delete data_; } + +static void SetThreadName(const char* name) { SbThreadSetName(name); } + +static void* ThreadEntry(void* arg) { + Thread* thread = reinterpret_cast(arg); + // We take the lock here to make sure that pthread_create finished first since + // we don't know which thread will run first (the original thread or the new + // one). + { LockGuard lock_guard(&thread->data()->thread_creation_mutex_); } + SetThreadName(thread->name()); + // DCHECK_NE(thread->data()->thread_, kNoThread); + thread->NotifyStartedAndRun(); + + return nullptr; +} + +void Thread::set_name(const char* name) { + strncpy(name_, name, sizeof(name_)); + name_[sizeof(name_) - 1] = '\0'; +} + +void Thread::Start() { + data_->thread_ = + SbThreadCreate(stack_size_, kSbThreadNoPriority, kSbThreadNoAffinity, + true, name_, ThreadEntry, this); +} + +void Thread::Join() { SbThreadJoin(data_->thread_, nullptr); } + +Thread::LocalStorageKey Thread::CreateThreadLocalKey() { + return SbThreadCreateLocalKey(nullptr); +} + +void Thread::DeleteThreadLocalKey(LocalStorageKey key) { + SbThreadDestroyLocalKey(key); +} + +void* Thread::GetThreadLocal(LocalStorageKey key) { + return SbThreadGetLocalValue(key); +} + +void Thread::SetThreadLocal(LocalStorageKey key, void* value) { + bool result = SbThreadSetLocalValue(key, value); + DCHECK(result); +} + +class StarboardTimezoneCache : public TimezoneCache { + public: + double DaylightSavingsOffset(double time_ms) override { return 0.0; } + void Clear(TimeZoneDetection time_zone_detection) override {} + ~StarboardTimezoneCache() override {} + + protected: + static const int msPerSecond = 1000; +}; + +class StarboardDefaultTimezoneCache : public StarboardTimezoneCache { + public: + const char* LocalTimezone(double time_ms) override { + return SbTimeZoneGetName(); + } + double LocalTimeOffset(double time_ms, bool is_utc) override { + return SbTimeZoneGetCurrent() * 60000.0; + } + + ~StarboardDefaultTimezoneCache() override {} +}; + +TimezoneCache* OS::CreateTimezoneCache() { + return new StarboardDefaultTimezoneCache(); +} + +std::vector OS::GetSharedLibraryAddresses() { + SB_NOTIMPLEMENTED(); + return {}; +} + +void OS::SignalCodeMovingGC() { SB_NOTIMPLEMENTED(); } + +void OS::AdjustSchedulingParams() {} + +bool OS::DiscardSystemPages(void* address, size_t size) { + // Starboard API does not support this function yet. + return true; +} + +} // namespace base +} // namespace v8 diff --git a/src/base/platform/platform.h b/src/base/platform/platform.h index d5f59d1d7a..caa063944e 100644 --- a/src/base/platform/platform.h +++ b/src/base/platform/platform.h @@ -74,6 +74,9 @@ inline intptr_t InternalGetExistingThreadLocal(intptr_t index) { #elif defined(__APPLE__) && (V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64) +// tvOS simulator does not use intptr_t as TLS key. +#if !defined(V8_OS_STARBOARD) || !defined(TARGET_OS_SIMULATOR) + #define V8_FAST_TLS_SUPPORTED 1 extern V8_BASE_EXPORT intptr_t kMacTlsBaseOffset; @@ -94,6 +97,8 @@ inline intptr_t InternalGetExistingThreadLocal(intptr_t index) { return result; } +#endif // !defined(V8_OS_STARBOARD) || !defined(TARGET_OS_SIMULATOR) + #endif #endif // V8_NO_FAST_TLS @@ -323,7 +328,11 @@ inline void EnsureConsoleOutput() { class V8_BASE_EXPORT Thread { public: // Opaque data type for thread-local storage keys. +#if V8_OS_STARBOARD + using LocalStorageKey = SbThreadLocalKey; +#else using LocalStorageKey = int32_t; +#endif class Options { public: diff --git a/src/base/platform/semaphore.cc b/src/base/platform/semaphore.cc index 66464d8258..0cd04634ba 100644 --- a/src/base/platform/semaphore.cc +++ b/src/base/platform/semaphore.cc @@ -157,6 +157,21 @@ bool Semaphore::WaitFor(const TimeDelta& rel_time) { } } +#elif V8_OS_STARBOARD + +Semaphore::Semaphore(int count) : native_handle_(count) { DCHECK_GE(count, 0); } + +Semaphore::~Semaphore() {} + +void Semaphore::Signal() { native_handle_.Put(); } + +void Semaphore::Wait() { native_handle_.Take(); } + +bool Semaphore::WaitFor(const TimeDelta& rel_time) { + SbTime microseconds = rel_time.InMicroseconds(); + return native_handle_.TakeWait(microseconds); +} + #endif // V8_OS_MACOSX } // namespace base diff --git a/src/base/platform/semaphore.h b/src/base/platform/semaphore.h index c4937acadd..0c0b877da2 100644 --- a/src/base/platform/semaphore.h +++ b/src/base/platform/semaphore.h @@ -17,6 +17,10 @@ #include // NOLINT #endif +#if V8_OS_STARBOARD +#include "starboard/common/semaphore.h" +#endif + namespace v8 { namespace base { @@ -55,6 +59,8 @@ class V8_BASE_EXPORT Semaphore final { using NativeHandle = sem_t; #elif V8_OS_WIN using NativeHandle = HANDLE; +#elif V8_OS_STARBOARD + using NativeHandle = starboard::Semaphore; #endif NativeHandle& native_handle() { diff --git a/src/base/platform/time.cc b/src/base/platform/time.cc index e72f90d214..78574b776d 100644 --- a/src/base/platform/time.cc +++ b/src/base/platform/time.cc @@ -26,6 +26,10 @@ #include "src/base/logging.h" #include "src/base/platform/platform.h" +#if V8_OS_STARBOARD +#include "starboard/time.h" +#endif + namespace { #if V8_OS_MACOSX @@ -449,7 +453,13 @@ struct timeval Time::ToTimeval() const { return tv; } -#endif // V8_OS_WIN +#elif V8_OS_STARBOARD + +Time Time::Now() { return Time(SbTimeToPosix(SbTimeGetNow())); } + +Time Time::NowFromSystemTime() { return Now(); } + +#endif // V8_OS_STARBOARD // static TimeTicks TimeTicks::HighResolutionNow() { @@ -717,6 +727,8 @@ TimeTicks TimeTicks::Now() { ticks = (gethrtime() / Time::kNanosecondsPerMicrosecond); #elif V8_OS_POSIX ticks = ClockNow(CLOCK_MONOTONIC); +#elif V8_OS_STARBOARD + ticks = SbTimeGetMonotonicNow(); #else #error platform does not implement TimeTicks::HighResolutionNow. #endif // V8_OS_MACOSX @@ -740,7 +752,15 @@ bool TimeTicks::IsHighResolution() { bool ThreadTicks::IsSupported() { -#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ +#if V8_OS_STARBOARD +#if SB_API_VERSION >= 12 + return SbTimeIsTimeThreadNowSupported(); +#elif SB_HAS(TIME_THREAD_NOW) + return true; +#else + return false; +#endif +#elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ defined(V8_OS_MACOSX) || defined(V8_OS_ANDROID) || defined(V8_OS_SOLARIS) return true; #elif defined(V8_OS_WIN) @@ -752,7 +772,17 @@ bool ThreadTicks::IsSupported() { ThreadTicks ThreadTicks::Now() { -#if V8_OS_MACOSX +#if V8_OS_STARBOARD +#if SB_API_VERSION >= 12 + if (SbTimeIsTimeThreadNowSupported()) + return ThreadTicks(SbTimeGetMonotonicThreadNow()); + UNREACHABLE(); +#elif SB_HAS(TIME_THREAD_NOW) + return ThreadTicks(SbTimeGetMonotonicThreadNow()); +#else + UNREACHABLE(); +#endif +#elif V8_OS_MACOSX return ThreadTicks(ComputeThreadTicks()); #elif(defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \ defined(V8_OS_ANDROID)