1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28// Platform specific code for POSIX goes here. This is not a platform on its 29// own but contains the parts which are the same across POSIX platforms Linux, 30// Mac OS, FreeBSD and OpenBSD. 31 32#include "platform-posix.h" 33 34#include <unistd.h> 35#include <errno.h> 36#include <time.h> 37 38#include <sys/mman.h> 39#include <sys/socket.h> 40#include <sys/resource.h> 41#include <sys/time.h> 42#include <sys/types.h> 43#include <sys/stat.h> 44 45#include <arpa/inet.h> 46#include <netinet/in.h> 47#include <netdb.h> 48 49#undef MAP_TYPE 50 51#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 52#define LOG_TAG "v8" 53#include <android/log.h> 54#endif 55 56#include "v8.h" 57 58#include "codegen.h" 59#include "platform.h" 60 61namespace v8 { 62namespace internal { 63 64 65// Maximum size of the virtual memory. 0 means there is no artificial 66// limit. 67 68intptr_t OS::MaxVirtualMemory() { 69 struct rlimit limit; 70 int result = getrlimit(RLIMIT_DATA, &limit); 71 if (result != 0) return 0; 72 return limit.rlim_cur; 73} 74 75 76intptr_t OS::CommitPageSize() { 77 static intptr_t page_size = getpagesize(); 78 return page_size; 79} 80 81 82#ifndef __CYGWIN__ 83// Get rid of writable permission on code allocations. 84void OS::ProtectCode(void* address, const size_t size) { 85 mprotect(address, size, PROT_READ | PROT_EXEC); 86} 87 88 89// Create guard pages. 90void OS::Guard(void* address, const size_t size) { 91 mprotect(address, size, PROT_NONE); 92} 93#endif // __CYGWIN__ 94 95 96void* OS::GetRandomMmapAddr() { 97 Isolate* isolate = Isolate::UncheckedCurrent(); 98 // Note that the current isolate isn't set up in a call path via 99 // CpuFeatures::Probe. We don't care about randomization in this case because 100 // the code page is immediately freed. 101 if (isolate != NULL) { 102#ifdef V8_TARGET_ARCH_X64 103 uint64_t rnd1 = V8::RandomPrivate(isolate); 104 uint64_t rnd2 = V8::RandomPrivate(isolate); 105 uint64_t raw_addr = (rnd1 << 32) ^ rnd2; 106 // Currently available CPUs have 48 bits of virtual addressing. Truncate 107 // the hint address to 46 bits to give the kernel a fighting chance of 108 // fulfilling our placement request. 109 raw_addr &= V8_UINT64_C(0x3ffffffff000); 110#else 111 uint32_t raw_addr = V8::RandomPrivate(isolate); 112 // The range 0x20000000 - 0x60000000 is relatively unpopulated across a 113 // variety of ASLR modes (PAE kernel, NX compat mode, etc) and on macos 114 // 10.6 and 10.7. 115 raw_addr &= 0x3ffff000; 116 raw_addr += 0x20000000; 117#endif 118 return reinterpret_cast<void*>(raw_addr); 119 } 120 return NULL; 121} 122 123 124// ---------------------------------------------------------------------------- 125// Math functions 126 127double modulo(double x, double y) { 128 return fmod(x, y); 129} 130 131 132#define UNARY_MATH_FUNCTION(name, generator) \ 133static UnaryMathFunction fast_##name##_function = NULL; \ 134void init_fast_##name##_function() { \ 135 fast_##name##_function = generator; \ 136} \ 137double fast_##name(double x) { \ 138 return (*fast_##name##_function)(x); \ 139} 140 141UNARY_MATH_FUNCTION(sin, CreateTranscendentalFunction(TranscendentalCache::SIN)) 142UNARY_MATH_FUNCTION(cos, CreateTranscendentalFunction(TranscendentalCache::COS)) 143UNARY_MATH_FUNCTION(tan, CreateTranscendentalFunction(TranscendentalCache::TAN)) 144UNARY_MATH_FUNCTION(log, CreateTranscendentalFunction(TranscendentalCache::LOG)) 145UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction()) 146 147#undef MATH_FUNCTION 148 149 150void MathSetup() { 151 init_fast_sin_function(); 152 init_fast_cos_function(); 153 init_fast_tan_function(); 154 init_fast_log_function(); 155 init_fast_sqrt_function(); 156} 157 158 159double OS::nan_value() { 160 // NAN from math.h is defined in C99 and not in POSIX. 161 return NAN; 162} 163 164 165// ---------------------------------------------------------------------------- 166// POSIX date/time support. 167// 168 169int OS::GetUserTime(uint32_t* secs, uint32_t* usecs) { 170 struct rusage usage; 171 172 if (getrusage(RUSAGE_SELF, &usage) < 0) return -1; 173 *secs = usage.ru_utime.tv_sec; 174 *usecs = usage.ru_utime.tv_usec; 175 return 0; 176} 177 178 179double OS::TimeCurrentMillis() { 180 struct timeval tv; 181 if (gettimeofday(&tv, NULL) < 0) return 0.0; 182 return (static_cast<double>(tv.tv_sec) * 1000) + 183 (static_cast<double>(tv.tv_usec) / 1000); 184} 185 186 187int64_t OS::Ticks() { 188 // gettimeofday has microsecond resolution. 189 struct timeval tv; 190 if (gettimeofday(&tv, NULL) < 0) 191 return 0; 192 return (static_cast<int64_t>(tv.tv_sec) * 1000000) + tv.tv_usec; 193} 194 195 196double OS::DaylightSavingsOffset(double time) { 197 if (isnan(time)) return nan_value(); 198 time_t tv = static_cast<time_t>(floor(time/msPerSecond)); 199 struct tm* t = localtime(&tv); 200 if (NULL == t) return nan_value(); 201 return t->tm_isdst > 0 ? 3600 * msPerSecond : 0; 202} 203 204 205int OS::GetLastError() { 206 return errno; 207} 208 209 210// ---------------------------------------------------------------------------- 211// POSIX stdio support. 212// 213 214FILE* OS::FOpen(const char* path, const char* mode) { 215 FILE* file = fopen(path, mode); 216 if (file == NULL) return NULL; 217 struct stat file_stat; 218 if (fstat(fileno(file), &file_stat) != 0) return NULL; 219 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0); 220 if (is_regular_file) return file; 221 fclose(file); 222 return NULL; 223} 224 225 226bool OS::Remove(const char* path) { 227 return (remove(path) == 0); 228} 229 230 231FILE* OS::OpenTemporaryFile() { 232 return tmpfile(); 233} 234 235 236const char* const OS::LogFileOpenMode = "w"; 237 238 239void OS::Print(const char* format, ...) { 240 va_list args; 241 va_start(args, format); 242 VPrint(format, args); 243 va_end(args); 244} 245 246 247void OS::VPrint(const char* format, va_list args) { 248#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 249 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 250#else 251 vprintf(format, args); 252#endif 253} 254 255 256void OS::FPrint(FILE* out, const char* format, ...) { 257 va_list args; 258 va_start(args, format); 259 VFPrint(out, format, args); 260 va_end(args); 261} 262 263 264void OS::VFPrint(FILE* out, const char* format, va_list args) { 265#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 266 __android_log_vprint(ANDROID_LOG_INFO, LOG_TAG, format, args); 267#else 268 vfprintf(out, format, args); 269#endif 270} 271 272 273void OS::PrintError(const char* format, ...) { 274 va_list args; 275 va_start(args, format); 276 VPrintError(format, args); 277 va_end(args); 278} 279 280 281void OS::VPrintError(const char* format, va_list args) { 282#if defined(ANDROID) && !defined(V8_ANDROID_LOG_STDOUT) 283 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); 284#else 285 vfprintf(stderr, format, args); 286#endif 287} 288 289 290int OS::SNPrintF(Vector<char> str, const char* format, ...) { 291 va_list args; 292 va_start(args, format); 293 int result = VSNPrintF(str, format, args); 294 va_end(args); 295 return result; 296} 297 298 299int OS::VSNPrintF(Vector<char> str, 300 const char* format, 301 va_list args) { 302 int n = vsnprintf(str.start(), str.length(), format, args); 303 if (n < 0 || n >= str.length()) { 304 // If the length is zero, the assignment fails. 305 if (str.length() > 0) 306 str[str.length() - 1] = '\0'; 307 return -1; 308 } else { 309 return n; 310 } 311} 312 313 314#if defined(V8_TARGET_ARCH_IA32) 315static OS::MemCopyFunction memcopy_function = NULL; 316static LazyMutex memcopy_function_mutex = LAZY_MUTEX_INITIALIZER; 317// Defined in codegen-ia32.cc. 318OS::MemCopyFunction CreateMemCopyFunction(); 319 320// Copy memory area to disjoint memory area. 321void OS::MemCopy(void* dest, const void* src, size_t size) { 322 if (memcopy_function == NULL) { 323 ScopedLock lock(memcopy_function_mutex.Pointer()); 324 if (memcopy_function == NULL) { 325 OS::MemCopyFunction temp = CreateMemCopyFunction(); 326 MemoryBarrier(); 327 memcopy_function = temp; 328 } 329 } 330 // Note: here we rely on dependent reads being ordered. This is true 331 // on all architectures we currently support. 332 (*memcopy_function)(dest, src, size); 333#ifdef DEBUG 334 CHECK_EQ(0, memcmp(dest, src, size)); 335#endif 336} 337#endif // V8_TARGET_ARCH_IA32 338 339// ---------------------------------------------------------------------------- 340// POSIX string support. 341// 342 343char* OS::StrChr(char* str, int c) { 344 return strchr(str, c); 345} 346 347 348void OS::StrNCpy(Vector<char> dest, const char* src, size_t n) { 349 strncpy(dest.start(), src, n); 350} 351 352 353// ---------------------------------------------------------------------------- 354// POSIX socket support. 355// 356 357class POSIXSocket : public Socket { 358 public: 359 explicit POSIXSocket() { 360 // Create the socket. 361 socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 362 if (IsValid()) { 363 // Allow rapid reuse. 364 static const int kOn = 1; 365 int ret = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, 366 &kOn, sizeof(kOn)); 367 ASSERT(ret == 0); 368 USE(ret); 369 } 370 } 371 explicit POSIXSocket(int socket): socket_(socket) { } 372 virtual ~POSIXSocket() { Shutdown(); } 373 374 // Server initialization. 375 bool Bind(const int port); 376 bool Listen(int backlog) const; 377 Socket* Accept() const; 378 379 // Client initialization. 380 bool Connect(const char* host, const char* port); 381 382 // Shutdown socket for both read and write. 383 bool Shutdown(); 384 385 // Data Transimission 386 int Send(const char* data, int len) const; 387 int Receive(char* data, int len) const; 388 389 bool SetReuseAddress(bool reuse_address); 390 391 bool IsValid() const { return socket_ != -1; } 392 393 private: 394 int socket_; 395}; 396 397 398bool POSIXSocket::Bind(const int port) { 399 if (!IsValid()) { 400 return false; 401 } 402 403 sockaddr_in addr; 404 memset(&addr, 0, sizeof(addr)); 405 addr.sin_family = AF_INET; 406 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 407 addr.sin_port = htons(port); 408 int status = bind(socket_, 409 BitCast<struct sockaddr *>(&addr), 410 sizeof(addr)); 411 return status == 0; 412} 413 414 415bool POSIXSocket::Listen(int backlog) const { 416 if (!IsValid()) { 417 return false; 418 } 419 420 int status = listen(socket_, backlog); 421 return status == 0; 422} 423 424 425Socket* POSIXSocket::Accept() const { 426 if (!IsValid()) { 427 return NULL; 428 } 429 430 int socket = accept(socket_, NULL, NULL); 431 if (socket == -1) { 432 return NULL; 433 } else { 434 return new POSIXSocket(socket); 435 } 436} 437 438 439bool POSIXSocket::Connect(const char* host, const char* port) { 440 if (!IsValid()) { 441 return false; 442 } 443 444 // Lookup host and port. 445 struct addrinfo *result = NULL; 446 struct addrinfo hints; 447 memset(&hints, 0, sizeof(addrinfo)); 448 hints.ai_family = AF_INET; 449 hints.ai_socktype = SOCK_STREAM; 450 hints.ai_protocol = IPPROTO_TCP; 451 int status = getaddrinfo(host, port, &hints, &result); 452 if (status != 0) { 453 return false; 454 } 455 456 // Connect. 457 status = connect(socket_, result->ai_addr, result->ai_addrlen); 458 freeaddrinfo(result); 459 return status == 0; 460} 461 462 463bool POSIXSocket::Shutdown() { 464 if (IsValid()) { 465 // Shutdown socket for both read and write. 466 int status = shutdown(socket_, SHUT_RDWR); 467 close(socket_); 468 socket_ = -1; 469 return status == 0; 470 } 471 return true; 472} 473 474 475int POSIXSocket::Send(const char* data, int len) const { 476 int status = send(socket_, data, len, 0); 477 return status; 478} 479 480 481int POSIXSocket::Receive(char* data, int len) const { 482 int status = recv(socket_, data, len, 0); 483 return status; 484} 485 486 487bool POSIXSocket::SetReuseAddress(bool reuse_address) { 488 int on = reuse_address ? 1 : 0; 489 int status = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); 490 return status == 0; 491} 492 493 494bool Socket::SetUp() { 495 // Nothing to do on POSIX. 496 return true; 497} 498 499 500int Socket::LastError() { 501 return errno; 502} 503 504 505uint16_t Socket::HToN(uint16_t value) { 506 return htons(value); 507} 508 509 510uint16_t Socket::NToH(uint16_t value) { 511 return ntohs(value); 512} 513 514 515uint32_t Socket::HToN(uint32_t value) { 516 return htonl(value); 517} 518 519 520uint32_t Socket::NToH(uint32_t value) { 521 return ntohl(value); 522} 523 524 525Socket* OS::CreateSocket() { 526 return new POSIXSocket(); 527} 528 529 530} } // namespace v8::internal 531