Add thread-safety to creation of MemCopy and modulo functions.
authorwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Mar 2011 14:04:26 +0000 (14:04 +0000)
committerwhesse@chromium.org <whesse@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 30 Mar 2011 14:04:26 +0000 (14:04 +0000)
BUG=
TEST=release test-api MultipleIsolatesOnIndividualThreads on Windows X64 build.

Review URL: http://codereview.chromium.org/6777007

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7437 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/api.cc
src/ia32/codegen-ia32.cc
src/platform-posix.cc
src/platform-win32.cc
src/platform.h
src/v8utils.h
src/x64/codegen-x64.cc
test/cctest/test-utils.cc

index fb827f2..61838e3 100644 (file)
@@ -1302,7 +1302,7 @@ ScriptData* ScriptData::New(const char* data, int length) {
   }
   // Copy the data to align it.
   unsigned* deserialized_data = i::NewArray<unsigned>(deserialized_data_length);
-  i::MemCopy(deserialized_data, data, length);
+  i::OS::MemCopy(deserialized_data, data, length);
 
   return new i::ScriptDataImpl(
       i::Vector<unsigned>(deserialized_data, deserialized_data_length));
index cf990a0..2d17a72 100644 (file)
@@ -10174,7 +10174,7 @@ static void MemCopyWrapper(void* dest, const void* src, size_t size) {
 }
 
 
-MemCopyFunction CreateMemCopyFunction() {
+OS::MemCopyFunction CreateMemCopyFunction() {
   HandleScope scope;
   MacroAssembler masm(NULL, 1 * KB);
 
@@ -10198,7 +10198,7 @@ MemCopyFunction CreateMemCopyFunction() {
 
   if (FLAG_debug_code) {
     __ cmp(Operand(esp, kSizeOffset + stack_offset),
-           Immediate(kMinComplexMemCopy));
+           Immediate(OS::kMinComplexMemCopy));
     Label ok;
     __ j(greater_equal, &ok);
     __ int3();
@@ -10377,7 +10377,8 @@ MemCopyFunction CreateMemCopyFunction() {
   if (chunk == NULL) return &MemCopyWrapper;
   memcpy(chunk->GetStartAddress(), desc.buffer, desc.instr_size);
   CPU::FlushICache(chunk->GetStartAddress(), desc.instr_size);
-  return FUNCTION_CAST<MemCopyFunction>(chunk->GetStartAddress());
+  MemoryBarrier();
+  return FUNCTION_CAST<OS::MemCopyFunction>(chunk->GetStartAddress());
 }
 
 #undef __
index 1dd486e..8365352 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -205,6 +205,29 @@ int OS::VSNPrintF(Vector<char> str,
 }
 
 
+#if defined(V8_TARGET_ARCH_IA32)
+static OS::MemCopyFunction memcopy_function = NULL;
+static Mutex* memcopy_function_mutex = OS::CreateMutex();
+// Defined in codegen-ia32.cc.
+OS::MemCopyFunction CreateMemCopyFunction();
+
+// Copy memory area to disjoint memory area.
+void OS::MemCopy(void* dest, const void* src, size_t size) {
+  if (memcopy_function == NULL) {
+    ScopedLock lock(memcopy_function_mutex);
+    Isolate::EnsureDefaultIsolate();
+    if (memcopy_function == NULL) {
+      Release_Store(reinterpret_cast<AtomicWord*>(&memcopy_function),
+                    reinterpret_cast<AtomicWord>(CreateMemCopyFunction()));
+    }
+  }
+  (*memcopy_function)(dest, src, size);
+#ifdef DEBUG
+  CHECK_EQ(0, memcmp(dest, src, size));
+#endif
+}
+#endif  // V8_TARGET_ARCH_IA32
+
 // ----------------------------------------------------------------------------
 // POSIX string support.
 //
index 50a9e5b..0901fca 100644 (file)
@@ -176,16 +176,45 @@ double ceiling(double x) {
 
 static Mutex* limit_mutex = NULL;
 
+#if defined(V8_TARGET_ARCH_IA32)
+static OS::MemCopyFunction memcopy_function = NULL;
+static Mutex* memcopy_function_mutex = OS::CreateMutex();
+// Defined in codegen-ia32.cc.
+OS::MemCopyFunction CreateMemCopyFunction();
+
+// Copy memory area to disjoint memory area.
+void OS::MemCopy(void* dest, const void* src, size_t size) {
+  if (memcopy_function == NULL) {
+    ScopedLock lock(memcopy_function_mutex);
+    Isolate::EnsureDefaultIsolate();
+    if (memcopy_function == NULL) {
+      memcopy_function = CreateMemCopyFunction();
+    }
+  }
+  (*memcopy_function)(dest, src, size);
+#ifdef DEBUG
+  CHECK_EQ(0, memcmp(dest, src, size));
+#endif
+}
+#endif  // V8_TARGET_ARCH_IA32
 
 #ifdef _WIN64
 typedef double (*ModuloFunction)(double, double);
-
+static ModuloFunction modulo_function = NULL;
+static Mutex* modulo_function_mutex = OS::CreateMutex();
 // Defined in codegen-x64.cc.
 ModuloFunction CreateModuloFunction();
 
 double modulo(double x, double y) {
-  static ModuloFunction function = CreateModuloFunction();
-  return function(x, y);
+  if (modulo_function == NULL) {
+    ScopedLock lock(modulo_function_mutex);
+    Isolate::EnsureDefaultIsolate();
+    if (modulo_function == NULL) {
+      Release_Store(reinterpret_cast<AtomicWord*>(&modulo_function),
+                    reinterpret_cast<AtomicWord>(CreateModuloFunction()));
+    }
+  }
+  return (*modulo_function)(x, y);
 }
 #else  // Win32
 
index 09a28a5..a5b804e 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -303,6 +303,21 @@ class OS {
 
   static void ReleaseStore(volatile AtomicWord* ptr, AtomicWord value);
 
+#if defined(V8_TARGET_ARCH_IA32)
+  // Copy memory area to disjoint memory area.
+  static void MemCopy(void* dest, const void* src, size_t size);
+  // Limit below which the extra overhead of the MemCopy function is likely
+  // to outweigh the benefits of faster copying.
+  static const int kMinComplexMemCopy = 64;
+  typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
+
+#else  // V8_TARGET_ARCH_IA32
+  static void MemCopy(void* dest, const void* src, size_t size) {
+    memcpy(dest, src, size);
+  }
+  static const int kMinComplexMemCopy = 256;
+#endif  // V8_TARGET_ARCH_IA32
+
  private:
   static const int msPerSecond = 1000;
 
index 0aa53ca..87c5e7f 100644 (file)
@@ -254,51 +254,14 @@ class StringBuilder {
 };
 
 
-// Custom memcpy implementation for platforms where the standard version
-// may not be good enough.
-#if defined(V8_TARGET_ARCH_IA32)
-
-// The default memcpy on ia32 architectures is generally not as efficient
-// as possible. (If any further ia32 platforms are introduced where the
-// memcpy function is efficient, exclude them from this branch).
-
-typedef void (*MemCopyFunction)(void* dest, const void* src, size_t size);
-
-// Implemented in codegen-<arch>.cc.
-MemCopyFunction CreateMemCopyFunction();
-
-// Copy memory area to disjoint memory area.
-static inline void MemCopy(void* dest, const void* src, size_t size) {
-  static MemCopyFunction memcopy = CreateMemCopyFunction();
-  (*memcopy)(dest, src, size);
-#ifdef DEBUG
-  CHECK_EQ(0, memcmp(dest, src, size));
-#endif
-}
-
-// Limit below which the extra overhead of the MemCopy function is likely
-// to outweigh the benefits of faster copying.
-static const int kMinComplexMemCopy = 64;
-
-#else  // V8_TARGET_ARCH_IA32
-
-static inline void MemCopy(void* dest, const void* src, size_t size) {
-  memcpy(dest, src, size);
-}
-
-static const int kMinComplexMemCopy = 256;
-
-#endif  // V8_TARGET_ARCH_IA32
-
-
 // Copy from ASCII/16bit chars to ASCII/16bit chars.
 template <typename sourcechar, typename sinkchar>
 static inline void CopyChars(sinkchar* dest, const sourcechar* src, int chars) {
   sinkchar* limit = dest + chars;
 #ifdef V8_HOST_CAN_READ_UNALIGNED
   if (sizeof(*dest) == sizeof(*src)) {
-    if (chars >= static_cast<int>(kMinComplexMemCopy / sizeof(*dest))) {
-      MemCopy(dest, src, chars * sizeof(*dest));
+    if (chars >= static_cast<int>(OS::kMinComplexMemCopy / sizeof(*dest))) {
+      OS::MemCopy(dest, src, chars * sizeof(*dest));
       return;
     }
     // Number of characters in a uintptr_t.
index dc999b5..c8f1c04 100644 (file)
@@ -8824,7 +8824,10 @@ ModuloFunction CreateModuloFunction() {
 
   CodeDesc desc;
   masm.GetCode(&desc);
-  // Call the function from C++.
+  // Make sure that the compiled code is visible to all threads before
+  // returning the pointer to it.
+  MemoryBarrier();
+  // Call the function from C++ through this pointer.
   return FUNCTION_CAST<ModuloFunction>(buffer);
 }
 
index 018018a..e96fcd1 100644 (file)
@@ -89,8 +89,8 @@ void TestMemCopy(Vector<byte> src,
   memset(dst.start(), 0xFF, dst.length());
   byte* to = dst.start() + 32 + destination_alignment;
   byte* from = src.start() + source_alignment;
-  int length = kMinComplexMemCopy + length_alignment;
-  MemCopy(to, from, static_cast<size_t>(length));
+  int length = OS::kMinComplexMemCopy + length_alignment;
+  OS::MemCopy(to, from, static_cast<size_t>(length));
   printf("[%d,%d,%d]\n",
          source_alignment, destination_alignment, length_alignment);
   for (int i = 0; i < length; i++) {
@@ -104,7 +104,7 @@ void TestMemCopy(Vector<byte> src,
 
 TEST(MemCopy) {
   OS::Setup();
-  const int N = kMinComplexMemCopy + 128;
+  const int N = OS::kMinComplexMemCopy + 128;
   Vector<byte> buffer1 = Vector<byte>::New(N);
   Vector<byte> buffer2 = Vector<byte>::New(N);