v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
platform-starboard.cc
Go to the documentation of this file.
1// Copyright 2020 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Platform-specific code for Starboard goes here. Starboard is the platform
6// abstraction layer for Cobalt, an HTML5 container used mainly by YouTube
7// apps in the living room.
8
9#include <stdio.h>
10#include <sys/mman.h>
11
13#include "src/base/macros.h"
18#include "starboard/client_porting/eztime/eztime.h"
19#include "starboard/common/condition_variable.h"
20#include "starboard/common/log.h"
21#include "starboard/common/string.h"
22#include "starboard/common/time.h"
23#include "starboard/configuration.h"
24#include "starboard/configuration_constants.h"
25#include "starboard/time_zone.h"
26
27namespace v8 {
28namespace base {
29
30#ifdef __arm__
32 // GCC versions 4.6 and above define __ARM_PCS or __ARM_PCS_VFP to specify
33 // the Floating Point ABI used (PCS stands for Procedure Call Standard).
34 // We use these as well as a couple of other defines to statically determine
35 // what FP ABI used.
36 // GCC versions 4.4 and below don't support hard-fp.
37 // GCC versions 4.5 may support hard-fp without defining __ARM_PCS or
38 // __ARM_PCS_VFP.
39
40#define GCC_VERSION \
41 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
42#if GCC_VERSION >= 40600 && !defined(__clang__)
43#if defined(__ARM_PCS_VFP)
44 return true;
45#else
46 return false;
47#endif
48
49#elif GCC_VERSION < 40500 && !defined(__clang__)
50 return false;
51
52#else
53#if defined(__ARM_PCS_VFP)
54 return true;
55#elif defined(__ARM_PCS) || defined(__SOFTFP__) || defined(__SOFTFP) || \
56 !defined(__VFP_FP__)
57 return false;
58#else
59#error \
60 "Your version of compiler does not report the FP ABI compiled for." \
61 "Please report it on this issue" \
62 "http://code.google.com/p/v8/issues/detail?id=2140"
63
64#endif
65#endif
66#undef GCC_VERSION
67}
68#endif // def __arm__
69
70namespace {
71
73 platform_random_number_generator = LAZY_INSTANCE_INITIALIZER;
74static LazyMutex rng_mutex = LAZY_MUTEX_INITIALIZER;
75
76// We only use this stack size to get the topmost stack frame.
77const int kStackSize = 1;
78
79} // namespace
80
81void OS::Initialize(AbortMode abort_mode, const char* const gc_fake_mmap) {
82 g_abort_mode = abort_mode;
83 // This is only used on Posix, we don't need to use it for anything.
84}
85
86int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) {
87 const int64_t us_time = starboard::CurrentMonotonicThreadTime();
88 if (us_time == 0) return -1;
89 *secs = us_time / TimeConstants::kMicroSecondsPerSecond;
90 *usecs = us_time % TimeConstants::kMicroSecondsPerSecond;
91 return 0;
92}
93
94double OS::TimeCurrentMillis() { return Time::Now().ToJsTime(); }
95
97#if V8_TARGET_ARCH_ARM
98 // On EABI ARM targets this is required for fp correctness in the
99 // runtime system.
100 return 8;
101#elif V8_TARGET_ARCH_MIPS
102 return 8;
103#elif V8_TARGET_ARCH_S390X
104 return 8;
105#else
106 // Otherwise we just assume 16 byte alignment, i.e.:
107 // - With gcc 4.4 the tree vectorization optimizer can generate code
108 // that requires 16 byte alignment such as movdqa on x86.
109 // - Mac OS X, PPC and Solaris (64-bit) activation frames must
110 // be 16 byte-aligned; see "Mac OS X ABI Function Call Guide"
111 return 16;
112#endif
113}
114
115// static
116size_t OS::AllocatePageSize() { return kSbMemoryPageSize; }
117
118// static
119size_t OS::CommitPageSize() { return kSbMemoryPageSize; }
120
121// static
122void OS::SetRandomMmapSeed(int64_t seed) { SB_NOTIMPLEMENTED(); }
123
124// static
125void* OS::GetRandomMmapAddr() { return nullptr; }
126
127void* Allocate(void* address, size_t size, OS::MemoryPermission access) {
128 int prot_flags;
129 switch (access) {
131 prot_flags = PROT_NONE;
132 break;
134 prot_flags = PROT_READ | PROT_WRITE;
135 break;
136 default:
137 SB_LOG(ERROR) << "The requested memory allocation access is not"
138 " implemented for Starboard: "
139 << static_cast<int>(access);
140 return nullptr;
141 }
142 void* result = mmap(nullptr, size, prot_flags, MAP_PRIVATE | MAP_ANON, -1, 0);
143 if (result == MAP_FAILED) {
144 return nullptr;
145 }
146 return result;
147}
148
149// static
150void* OS::Allocate(void* address, size_t size, size_t alignment,
151 MemoryPermission access) {
152 size_t page_size = AllocatePageSize();
153 DCHECK_EQ(0, size % page_size);
154 DCHECK_EQ(0, alignment % page_size);
155 address = AlignedAddress(address, alignment);
156 // Add the maximum misalignment so we are guaranteed an aligned base address.
157 size_t request_size = size + (alignment - page_size);
158 request_size = RoundUp(request_size, OS::AllocatePageSize());
159 void* result = base::Allocate(address, request_size, access);
160 if (result == nullptr) return nullptr;
161
162 // Unmap memory allocated before the aligned base address.
163 uint8_t* base = static_cast<uint8_t*>(result);
164 uint8_t* aligned_base = reinterpret_cast<uint8_t*>(
165 RoundUp(reinterpret_cast<uintptr_t>(base), alignment));
166 if (aligned_base != base) {
167 DCHECK_LT(base, aligned_base);
168 size_t prefix_size = static_cast<size_t>(aligned_base - base);
169 Free(base, prefix_size);
170 request_size -= prefix_size;
171 }
172 // Unmap memory allocated after the potentially unaligned end.
173 if (size != request_size) {
174 DCHECK_LT(size, request_size);
175 size_t suffix_size = request_size - size;
176 Free(aligned_base + size, suffix_size);
177 request_size -= suffix_size;
178 }
179
180 DCHECK_EQ(size, request_size);
181 return static_cast<void*>(aligned_base);
182}
183
184// static
185void OS::Free(void* address, const size_t size) {
186 CHECK_EQ(munmap(address, size), 0);
187}
188
189// static
190void OS::Release(void* address, size_t size) {
191 CHECK_EQ(munmap(address, size), 0);
192}
193
194// static
195bool OS::SetPermissions(void* address, size_t size, MemoryPermission access) {
196 int new_protection;
197 switch (access) {
199 new_protection = PROT_NONE;
200 break;
202 new_protection = PROT_READ;
204 new_protection = PROT_READ | PROT_WRITE;
205 break;
207#if SB_CAN(MAP_EXECUTABLE_MEMORY)
208 new_protection = PROT_READ | PROT_EXEC;
209#else
210 UNREACHABLE();
211#endif
212 break;
213 default:
214 // All other types are not supported by Starboard.
215 return false;
216 }
217 return mprotect(address, size, new_protection) == 0;
218}
219
220// static
221bool OS::RecommitPages(void* address, size_t size, MemoryPermission access) {
222 return SetPermissions(address, size, access);
223}
224
225// static
226bool OS::HasLazyCommits() {
227 SB_NOTIMPLEMENTED();
228 return false;
229}
230
231void OS::Sleep(TimeDelta interval) { SbThreadSleep(interval.InMicroseconds()); }
232
233void OS::Abort() { SbSystemBreakIntoDebugger(); }
234
235void OS::DebugBreak() { SbSystemBreakIntoDebugger(); }
236
238 public:
240 void* memory() const final {
241 SB_NOTIMPLEMENTED();
242 return nullptr;
243 }
244 size_t size() const final {
245 SB_NOTIMPLEMENTED();
246 return 0u;
247 }
248};
249
250// static
252 FileMode mode) {
253 SB_NOTIMPLEMENTED();
254 return nullptr;
255}
256
257// static
259 size_t size, void* initial) {
260 SB_NOTIMPLEMENTED();
261 return nullptr;
262}
263
265
267 SB_NOTIMPLEMENTED();
268 return 0;
269}
270
271int OS::GetCurrentThreadIdInternal() { return SbThreadGetId(); }
272
273int OS::GetLastError() { return SbSystemGetLastError(); }
274
275// ----------------------------------------------------------------------------
276// POSIX stdio support.
277//
278
279FILE* OS::FOpen(const char* path, const char* mode) {
280 SB_NOTIMPLEMENTED();
281 return nullptr;
282}
283
284bool OS::Remove(const char* path) {
285 SB_NOTIMPLEMENTED();
286 return false;
287}
288
289char OS::DirectorySeparator() { return kSbFileSepChar; }
290
291bool OS::isDirectorySeparator(const char ch) {
292 return ch == DirectorySeparator();
293}
294
295FILE* OS::OpenTemporaryFile() {
296 SB_NOTIMPLEMENTED();
297 return nullptr;
298}
299
300const char* const OS::LogFileOpenMode = "\0";
301
302void OS::Print(const char* format, ...) {
303 va_list args;
304 va_start(args, format);
305 VPrint(format, args);
306 va_end(args);
307}
308
309void OS::VPrint(const char* format, va_list args) {
310 SbLogRawFormat(format, args);
311}
312
313void OS::FPrint(FILE* out, const char* format, ...) {
314 va_list args;
315 va_start(args, format);
316 VPrintError(format, args);
317 va_end(args);
318}
319
320void OS::VFPrint(FILE* out, const char* format, va_list args) {
321 SbLogRawFormat(format, args);
322}
323
324void OS::PrintError(const char* format, ...) {
325 va_list args;
326 va_start(args, format);
327 VPrintError(format, args);
328 va_end(args);
329}
330
331void OS::VPrintError(const char* format, va_list args) {
332 // Starboard has no concept of stderr vs stdout.
333 SbLogRawFormat(format, args);
334}
335
336int OS::SNPrintF(char* str, int length, const char* format, ...) {
337 va_list args;
338 va_start(args, format);
339 int result = VSNPrintF(str, length, format, args);
340 va_end(args);
341 return result;
342}
343
344int OS::VSNPrintF(char* str, int length, const char* format, va_list args) {
345 int n = vsnprintf(str, length, format, args);
346 if (n < 0 || n >= length) {
347 // If the length is zero, the assignment fails.
348 if (length > 0) str[length - 1] = '\0';
349 return -1;
350 } else {
351 return n;
352 }
353}
354
355// ----------------------------------------------------------------------------
356// POSIX string support.
357//
358
359void OS::StrNCpy(char* dest, int length, const char* src, size_t n) {
360 strncpy(dest, src, n);
361}
362
363// ----------------------------------------------------------------------------
364// POSIX thread support.
365//
366
367class Thread::PlatformData {
368 public:
369 PlatformData() : thread_(kSbThreadInvalid) {}
370 SbThread thread_; // Thread handle for pthread.
371 // Synchronizes thread creation
372 Mutex thread_creation_mutex_;
373};
374
375Thread::Thread(const Options& options)
376 : data_(new PlatformData),
377 stack_size_(options.stack_size()),
378 start_semaphore_(nullptr) {
379 set_name(options.name());
380}
381
382Thread::~Thread() { delete data_; }
383
384static void SetThreadName(const char* name) { SbThreadSetName(name); }
385
386static void* ThreadEntry(void* arg) {
387 Thread* thread = reinterpret_cast<Thread*>(arg);
388 // We take the lock here to make sure that pthread_create finished first since
389 // we don't know which thread will run first (the original thread or the new
390 // one).
391 { LockGuard<Mutex> lock_guard(&thread->data()->thread_creation_mutex_); }
392 SetThreadName(thread->name());
393 // DCHECK_NE(thread->data()->thread_, kNoThread);
394 thread->NotifyStartedAndRun();
395
396 return nullptr;
397}
398
399void Thread::set_name(const char* name) {
400 strncpy(name_, name, sizeof(name_));
401 name_[sizeof(name_) - 1] = '\0';
402}
403
404bool Thread::Start() {
405 data_->thread_ =
406 SbThreadCreate(stack_size_, kSbThreadNoPriority, kSbThreadNoAffinity,
407 true, name_, ThreadEntry, this);
408 return SbThreadIsValid(data_->thread_);
409}
410
411void Thread::Join() { SbThreadJoin(data_->thread_, nullptr); }
412
414 return SbThreadCreateLocalKey(nullptr);
415}
416
418 SbThreadDestroyLocalKey(key);
419}
420
422 return SbThreadGetLocalValue(key);
423}
424
425void Thread::SetThreadLocal(LocalStorageKey key, void* value) {
426 bool result = SbThreadSetLocalValue(key, value);
427 DCHECK(result);
428}
429
431 public:
432 void Clear(TimeZoneDetection time_zone_detection) override {}
434
435 protected:
436 static const int msPerSecond = 1000;
437};
438
440 public:
441 const char* LocalTimezone(double time_ms) override {
442 return SbTimeZoneGetName();
443 }
444 double LocalTimeOffset(double time_ms, bool is_utc) override {
445 // SbTimeZoneGetCurrent returns an offset west of Greenwich, which has the
446 // opposite sign V8 expects.
447 // The starboard function returns offset in minutes. We convert to return
448 // value in milliseconds.
449 return SbTimeZoneGetCurrent() * 60.0 * msPerSecond * (-1);
450 }
451 double DaylightSavingsOffset(double time_ms) override {
452 int64_t posix_microseconds = starboard::CurrentPosixTime();
453 EzTimeValue value = {
454 posix_microseconds / TimeConstants::kMicroSecondsPerSecond,
455 (int32_t)(posix_microseconds % TimeConstants::kMicroSecondsPerSecond)
456 };
457 EzTimeExploded ez_exploded;
458 bool result =
459 EzTimeValueExplode(&value, kEzTimeZoneLocal, &ez_exploded, NULL);
460 return ez_exploded.tm_isdst > 0 ? 3600 * msPerSecond : 0;
461 }
462
464};
465
466TimezoneCache* OS::CreateTimezoneCache() {
467 return new StarboardDefaultTimezoneCache();
468}
469
470std::vector<OS::SharedLibraryAddress> OS::GetSharedLibraryAddresses() {
471 SB_NOTIMPLEMENTED();
472 return {};
473}
474
475void OS::SignalCodeMovingGC() { SB_NOTIMPLEMENTED(); }
476
478
479std::optional<OS::MemoryRange> OS::GetFirstFreeMemoryRangeWithin(
480 OS::Address boundary_start, OS::Address boundary_end, size_t minimum_size,
481 size_t alignment) {
482 return std::nullopt;
483}
484
485bool OS::DiscardSystemPages(void* address, size_t size) {
486 // Starboard API does not support this function yet.
487 return true;
488}
489
490// static
492 SB_NOTIMPLEMENTED();
493 return nullptr;
494}
495
496// static
498 void* addresses[kStackSize];
499 const size_t count = SbSystemGetStack(addresses, kStackSize);
500 if (count > 0) {
501 return addresses[0];
502 } else {
503 return nullptr;
504 }
505}
506
507} // namespace base
508} // namespace v8
uint8_t data_[MAX_STACK_LENGTH]
static MemoryMappedFile * create(const char *name, size_t size, void *initial)
static MemoryMappedFile * open(const char *name, FileMode mode=FileMode::kReadWrite)
static void Sleep(TimeDelta interval)
static void * GetRandomMmapAddr()
static void SignalCodeMovingGC()
static bool ArmUsingHardFloat()
static static va_list args
Definition platform.h:200
static bool HasLazyCommits()
static V8_WARN_UNUSED_RESULT bool DiscardSystemPages(void *address, size_t size)
static size_t AllocatePageSize()
static void Abort()
static const char *const LogFileOpenMode
Definition platform.h:194
static int GetCurrentThreadIdInternal()
static int GetLastError()
static V8_WARN_UNUSED_RESULT bool SetPermissions(void *address, size_t size, MemoryPermission access)
static FILE * OpenTemporaryFile()
static FILE * FOpen(const char *path, const char *mode)
static void Initialize(AbortMode abort_mode, const char *const gc_fake_mmap)
static int GetCurrentProcessId()
static size_t CommitPageSize()
static void Release(void *address, size_t size)
static V8_WARN_UNUSED_RESULT bool RecommitPages(void *address, size_t size, MemoryPermission access)
static std::vector< SharedLibraryAddress > GetSharedLibraryAddresses()
static char DirectorySeparator()
static void StrNCpy(char *dest, int length, const char *src, size_t n)
static int GetUserTime(uint32_t *secs, uint32_t *usecs)
static int ActivationFrameAlignment()
uintptr_t Address
Definition platform.h:315
static V8_WARN_UNUSED_RESULT void * Allocate(void *address, size_t size, size_t alignment, MemoryPermission access)
static TimezoneCache * CreateTimezoneCache()
static double TimeCurrentMillis()
static bool isDirectorySeparator(const char ch)
static void SetRandomMmapSeed(int64_t seed)
friend class MemoryMappedFile
Definition platform.h:365
static void Free(void *address, size_t size)
static std::optional< MemoryRange > GetFirstFreeMemoryRangeWithin(Address boundary_start, Address boundary_end, size_t minimum_size, size_t alignment)
static bool Remove(const char *path)
static void AdjustSchedulingParams()
static void DebugBreak()
static StackSlot GetStackStart()
static V8_NOINLINE StackSlot GetCurrentStackPosition()
const char * LocalTimezone(double time_ms) override
double LocalTimeOffset(double time_ms, bool is_utc) override
double DaylightSavingsOffset(double time_ms) override
void Clear(TimeZoneDetection time_zone_detection) override
Thread(const Options &options)
V8_WARN_UNUSED_RESULT bool Start()
int32_t LocalStorageKey
Definition platform.h:541
static void DeleteThreadLocalKey(LocalStorageKey key)
PlatformData * data_
Definition platform.h:633
static LocalStorageKey CreateThreadLocalKey()
static void * GetThreadLocal(LocalStorageKey key)
void set_name(const char *name)
char name_[kMaxThreadNameLength]
Definition platform.h:635
static void SetThreadLocal(LocalStorageKey key, void *value)
static Time Now()
double ToJsTime() const
Definition time.cc:502
ZoneVector< RpoNumber > & result
#define LAZY_INSTANCE_INITIALIZER
int n
Definition mul-fft.cc:296
#define LAZY_MUTEX_INITIALIZER
Definition mutex.h:105
void * Allocate(void *address, size_t size, OS::MemoryPermission access)
static void * ThreadEntry(void *arg)
AbortMode g_abort_mode
Definition abort-mode.cc:10
static void SetThreadName(const char *name)
int VSNPrintF(Vector< char > str, const char *format, va_list args)
Definition strings.cc:16
LazyStaticInstance< Mutex, DefaultConstructTrait< Mutex >, ThreadSafeInitOnceTrait >::type LazyMutex
Definition mutex.h:103
#define UNREACHABLE()
Definition logging.h:67
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
void * AlignedAddress(void *address, size_t alignment)
Definition macros.h:407
typename LazyStaticInstance< T, CreateTrait, InitOnceTrait, DestroyTrait >::type type
std::unique_ptr< ValueMirror > key