Bug 988831 - support memory mapped files in Windows. r=ehoogeveen
authorBenjamin Dahse <bd339@tuta.io>
Thu, 30 Jun 2016 14:32:13 +0200
changeset 303290 c0be190ee52a816be2fe5639d6ecb3d12e011a3d
parent 303289 cd9485fc83bf4056b6764f215f990fe9b84ba415
child 303291 09008468049e90a78e8194b307677e038078c9b6
push id79038
push usersfink@mozilla.com
push dateThu, 30 Jun 2016 22:47:04 +0000
treeherdermozilla-inbound@c0be190ee52a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersehoogeveen
bugs988831
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 988831 - support memory mapped files in Windows. r=ehoogeveen
b2g/app/b2g.js
dom/base/test/chrome.ini
dom/xhr/XMLHttpRequestMainThread.cpp
js/src/gc/Memory.cpp
modules/libpref/init/all.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -1016,19 +1016,17 @@ pref("services.mobileid.server.uri", "ht
 
 pref("identity.fxaccounts.remote.oauth.uri", "https://oauth.accounts.firefox.com/v1");
 pref("identity.fxaccounts.remote.profile.uri", "https://profile.accounts.firefox.com/v1");
 
 // Disable Firefox Accounts device registration until bug 1238895 is fixed.
 pref("identity.fxaccounts.skipDeviceRegistration", true);
 
 // Enable mapped array buffer.
-#ifndef XP_WIN
 pref("dom.mapped_arraybuffer.enabled", true);
-#endif
 
 // SystemUpdate API
 pref("dom.system_update.enabled", true);
 
 // UDPSocket API
 pref("dom.udpsocket.enabled", true);
 
 // Enable TV Manager API
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -15,13 +15,11 @@ support-files = file_navigator_resolve_i
 [test_sendQueryContentAndSelectionSetEvent.html]
 [test_bug1016960.html]
 [test_copypaste.xul]
 subsuite = clipboard
 [test_messagemanager_principal.html]
 [test_messagemanager_send_principal.html]
 skip-if = buildapp == 'mulet'
 [test_bug945152.html]
-run-if = os == 'linux'
 [test_bug1008126.html]
-run-if = os == 'linux'
 [test_sandboxed_blob_uri.html]
 [test_websocket_frame.html]
--- a/dom/xhr/XMLHttpRequestMainThread.cpp
+++ b/dom/xhr/XMLHttpRequestMainThread.cpp
@@ -2723,17 +2723,17 @@ XMLHttpRequestMainThread::Send(nsIVarian
   if (!IsSystemXHR()) {
     nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
     loadInfo->SetCorsPreflightInfo(mCORSUnsafeHeaders,
                                    mState & XML_HTTP_REQUEST_HAD_UPLOAD_LISTENERS_ON_SEND);
   }
 
   mIsMappedArrayBuffer = false;
   if (mResponseType == XMLHttpRequestResponseType::Arraybuffer &&
-      Preferences::GetBool("dom.mapped_arraybuffer.enabled", false)) {
+      Preferences::GetBool("dom.mapped_arraybuffer.enabled", true)) {
     nsCOMPtr<nsIURI> uri;
     nsAutoCString scheme;
 
     rv = mChannel->GetURI(getter_AddRefs(uri));
     if (NS_SUCCEEDED(rv)) {
       uri->GetScheme(scheme);
       if (scheme.LowerCaseEqualsLiteral("app") ||
           scheme.LowerCaseEqualsLiteral("jar")) {
@@ -3752,21 +3752,16 @@ ArrayBufferBuilder::getArrayBuffer(JSCon
   mDataPtr = nullptr;
   return obj;
 }
 
 nsresult
 ArrayBufferBuilder::mapToFileInPackage(const nsCString& aFile,
                                        nsIFile* aJarFile)
 {
-#ifdef XP_WIN
-  // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform.
-  MOZ_CRASH("Not implemented");
-  return NS_ERROR_NOT_IMPLEMENTED;
-#else
   nsresult rv;
 
   // Open Jar file to get related attributes of target file.
   RefPtr<nsZipArchive> zip = new nsZipArchive();
   rv = zip->OpenArchive(aJarFile);
   if (NS_FAILED(rv)) {
     return rv;
   }
@@ -3788,17 +3783,16 @@ ArrayBufferBuilder::mapToFileInPackage(c
     mMapPtr = JS_CreateMappedArrayBufferContents(PR_FileDesc2NativeHandle(pr_fd),
                                                  offset, size);
     if (mMapPtr) {
       mLength = size;
       return NS_OK;
     }
   }
   return NS_ERROR_FAILURE;
-#endif
 }
 
 /* static */ bool
 ArrayBufferBuilder::areOverlappingRegions(const uint8_t* aStart1,
                                           uint32_t aLength1,
                                           const uint8_t* aStart2,
                                           uint32_t aLength2)
 {
--- a/js/src/gc/Memory.cpp
+++ b/js/src/gc/Memory.cpp
@@ -275,16 +275,71 @@ size_t
 GetPageFaultCount()
 {
     PROCESS_MEMORY_COUNTERS pmc;
     if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
         return 0;
     return pmc.PageFaultCount;
 }
 
+// On Windows the minimum size for a mapping is the allocation granularity
+// (64KiB in practice), so mapping very small buffers is potentially wasteful.
+void*
+AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment)
+{
+    // The allocation granularity must be a whole multiple of the alignment and
+    // the caller must request an aligned offset to satisfy Windows' and the
+    // caller's alignment requirements.
+    if (allocGranularity % alignment != 0 || offset % alignment != 0)
+        return nullptr;
+
+    // Make sure file exists and do sanity check for offset and size.
+    HANDLE hFile = reinterpret_cast<HANDLE>(intptr_t(fd));
+    MOZ_ASSERT(hFile != INVALID_HANDLE_VALUE);
+
+    uint32_t fSizeHgh;
+    uint32_t fSizeLow = GetFileSize(hFile, LPDWORD(&fSizeHgh));
+    if (fSizeLow == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
+        return nullptr;
+
+    uint64_t fSize = (uint64_t(fSizeHgh) << 32) + fSizeLow;
+    if (offset >= size_t(fSize) || length == 0 || length > fSize - offset)
+        return nullptr;
+
+    uint64_t mapSize = length + offset;
+    HANDLE hMap = CreateFileMapping(hFile, nullptr, PAGE_READONLY, mapSize >> 32, mapSize, nullptr);
+    if (!hMap)
+        return nullptr;
+
+    // MapViewOfFile requires the offset to be a whole multiple of the
+    // allocation granularity.
+    size_t alignOffset = offset - (offset % allocGranularity);
+    size_t alignLength = length + (offset % allocGranularity);
+    void* map = MapViewOfFile(hMap, FILE_MAP_COPY, 0, alignOffset, alignLength);
+    CloseHandle(hMap);
+    if (!map)
+        return nullptr;
+
+    return reinterpret_cast<void*>(uintptr_t(map) + (offset - alignOffset));
+}
+
+void
+DeallocateMappedContent(void* p, size_t /*length*/)
+{
+    if (!p)
+        return;
+
+    // Calculate the address originally returned by MapViewOfFile.
+    // This is required because AllocateMappedContent returns a pointer that
+    // might be offset into the view, necessitated by the requirement that the
+    // beginning of a view must be aligned with the allocation granularity.
+    uintptr_t map = uintptr_t(p) - (uintptr_t(p) % allocGranularity);
+    MOZ_ALWAYS_TRUE(UnmapViewOfFile(reinterpret_cast<void*>(map)));
+}
+
 #  else // Various APIs are unavailable.
 
 void*
 MapAlignedPages(size_t size, size_t alignment)
 {
     MOZ_ASSERT(size >= alignment);
     MOZ_ASSERT(size % alignment == 0);
     MOZ_ASSERT(size % pageSize == 0);
@@ -323,32 +378,32 @@ MarkPagesInUse(void* p, size_t size)
 
 size_t
 GetPageFaultCount()
 {
     // GetProcessMemoryInfo is unavailable.
     return 0;
 }
 
-#  endif
-
 void*
 AllocateMappedContent(int fd, size_t offset, size_t length, size_t alignment)
 {
-    // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform.
+    // Not implemented.
     return nullptr;
 }
 
 // Deallocate mapped memory for object.
 void
 DeallocateMappedContent(void* p, size_t length)
 {
-    // TODO: Bug 988813 - Support memory mapped array buffer for Windows platform.
+    // Not implemented.
 }
 
+#  endif
+
 #elif defined(SOLARIS)
 
 #ifndef MAP_NOSYNC
 # define MAP_NOSYNC 0
 #endif
 
 void
 InitMemorySubsystem()
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5048,18 +5048,18 @@ pref("dom.mobileconnection.enabled", fal
 pref("dom.voicemail.enabled", true);
 #else
 pref("dom.voicemail.enabled", false);
 #endif
 // Numeric default service id for Voice Mail API calls with |serviceId|
 // parameter omitted.
 pref("dom.voicemail.defaultServiceId", 0);
 
-// Disable mapped array buffer by default.
-pref("dom.mapped_arraybuffer.enabled", false);
+// Enable mapped array buffer by default.
+pref("dom.mapped_arraybuffer.enabled", true);
 
 // The tables used for Safebrowsing phishing and malware checks.
 pref("urlclassifier.malwareTable", "goog-malware-shavar,goog-unwanted-shavar,test-malware-simple,test-unwanted-simple");
 pref("urlclassifier.phishTable", "goog-phish-shavar,test-phish-simple");
 
 // Tables for application reputation.
 pref("urlclassifier.downloadBlockTable", "goog-badbinurl-shavar");