1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/xpcom/base/AvailableMemoryTracker.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,550 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "mozilla/AvailableMemoryTracker.h" 1.11 + 1.12 +#if defined(XP_WIN) 1.13 +#include "prinrval.h" 1.14 +#include "prenv.h" 1.15 +#include "nsIMemoryReporter.h" 1.16 +#include "nsMemoryPressure.h" 1.17 +#endif 1.18 + 1.19 +#include "nsIObserver.h" 1.20 +#include "nsIObserverService.h" 1.21 +#include "nsIRunnable.h" 1.22 +#include "nsISupports.h" 1.23 +#include "nsThreadUtils.h" 1.24 + 1.25 +#include "mozilla/Preferences.h" 1.26 +#include "mozilla/Services.h" 1.27 + 1.28 +#if defined(XP_WIN) 1.29 +# include "nsWindowsDllInterceptor.h" 1.30 +# include <windows.h> 1.31 +#endif 1.32 + 1.33 +#if defined(MOZ_MEMORY) 1.34 +# include "mozmemory.h" 1.35 +#endif // MOZ_MEMORY 1.36 + 1.37 +using namespace mozilla; 1.38 + 1.39 +namespace { 1.40 + 1.41 +#if defined(XP_WIN) 1.42 + 1.43 +// We don't want our diagnostic functions to call malloc, because that could 1.44 +// call VirtualAlloc, and we'd end up back in here! So here are a few simple 1.45 +// debugging macros (modeled on jemalloc's), which hopefully won't allocate. 1.46 + 1.47 +// #define LOGGING_ENABLED 1.48 + 1.49 +#ifdef LOGGING_ENABLED 1.50 + 1.51 +#define LOG(msg) \ 1.52 + do { \ 1.53 + safe_write(msg); \ 1.54 + safe_write("\n"); \ 1.55 + } while(0) 1.56 + 1.57 +#define LOG2(m1, m2) \ 1.58 + do { \ 1.59 + safe_write(m1); \ 1.60 + safe_write(m2); \ 1.61 + safe_write("\n"); \ 1.62 + } while(0) 1.63 + 1.64 +#define LOG3(m1, m2, m3) \ 1.65 + do { \ 1.66 + safe_write(m1); \ 1.67 + safe_write(m2); \ 1.68 + safe_write(m3); \ 1.69 + safe_write("\n"); \ 1.70 + } while(0) 1.71 + 1.72 +#define LOG4(m1, m2, m3, m4) \ 1.73 + do { \ 1.74 + safe_write(m1); \ 1.75 + safe_write(m2); \ 1.76 + safe_write(m3); \ 1.77 + safe_write(m4); \ 1.78 + safe_write("\n"); \ 1.79 + } while(0) 1.80 + 1.81 +#else 1.82 + 1.83 +#define LOG(msg) 1.84 +#define LOG2(m1, m2) 1.85 +#define LOG3(m1, m2, m3) 1.86 +#define LOG4(m1, m2, m3, m4) 1.87 + 1.88 +#endif 1.89 + 1.90 +void safe_write(const char *a) 1.91 +{ 1.92 + // Well, puts isn't exactly "safe", but at least it doesn't call malloc... 1.93 + fputs(a, stdout); 1.94 +} 1.95 + 1.96 +void safe_write(uint64_t x) 1.97 +{ 1.98 + // 2^64 is 20 decimal digits. 1.99 + const unsigned int max_len = 21; 1.100 + char buf[max_len]; 1.101 + buf[max_len - 1] = '\0'; 1.102 + 1.103 + uint32_t i; 1.104 + for (i = max_len - 2; i < max_len && x > 0; i--) 1.105 + { 1.106 + buf[i] = "0123456789"[x % 10]; 1.107 + x /= 10; 1.108 + } 1.109 + 1.110 + safe_write(&buf[i + 1]); 1.111 +} 1.112 + 1.113 +#ifdef DEBUG 1.114 +#define DEBUG_WARN_IF_FALSE(cond, msg) \ 1.115 + do { \ 1.116 + if (!(cond)) { \ 1.117 + safe_write(__FILE__); \ 1.118 + safe_write(":"); \ 1.119 + safe_write(__LINE__); \ 1.120 + safe_write(" "); \ 1.121 + safe_write(msg); \ 1.122 + safe_write("\n"); \ 1.123 + } \ 1.124 + } while(0) 1.125 +#else 1.126 +#define DEBUG_WARN_IF_FALSE(cond, msg) 1.127 +#endif 1.128 + 1.129 +uint32_t sLowVirtualMemoryThreshold = 0; 1.130 +uint32_t sLowCommitSpaceThreshold = 0; 1.131 +uint32_t sLowPhysicalMemoryThreshold = 0; 1.132 +uint32_t sLowMemoryNotificationIntervalMS = 0; 1.133 + 1.134 +Atomic<uint32_t> sNumLowVirtualMemEvents; 1.135 +Atomic<uint32_t> sNumLowCommitSpaceEvents; 1.136 +Atomic<uint32_t> sNumLowPhysicalMemEvents; 1.137 + 1.138 +WindowsDllInterceptor sKernel32Intercept; 1.139 +WindowsDllInterceptor sGdi32Intercept; 1.140 + 1.141 +// Has Init() been called? 1.142 +bool sInitialized = false; 1.143 + 1.144 +// Has Activate() been called? The hooks don't do anything until this happens. 1.145 +bool sHooksActive = false; 1.146 + 1.147 +// Alas, we'd like to use mozilla::TimeStamp, but we can't, because it acquires 1.148 +// a lock! 1.149 +volatile bool sHasScheduledOneLowMemoryNotification = false; 1.150 +volatile PRIntervalTime sLastLowMemoryNotificationTime; 1.151 + 1.152 +// These are function pointers to the functions we wrap in Init(). 1.153 + 1.154 +void* (WINAPI *sVirtualAllocOrig) 1.155 + (LPVOID aAddress, SIZE_T aSize, DWORD aAllocationType, DWORD aProtect); 1.156 + 1.157 +void* (WINAPI *sMapViewOfFileOrig) 1.158 + (HANDLE aFileMappingObject, DWORD aDesiredAccess, 1.159 + DWORD aFileOffsetHigh, DWORD aFileOffsetLow, 1.160 + SIZE_T aNumBytesToMap); 1.161 + 1.162 +HBITMAP (WINAPI *sCreateDIBSectionOrig) 1.163 + (HDC aDC, const BITMAPINFO *aBitmapInfo, 1.164 + UINT aUsage, VOID **aBits, 1.165 + HANDLE aSection, DWORD aOffset); 1.166 + 1.167 +/** 1.168 + * Fire a memory pressure event if it's been long enough since the last one we 1.169 + * fired. 1.170 + */ 1.171 +bool MaybeScheduleMemoryPressureEvent() 1.172 +{ 1.173 + // If this interval rolls over, we may fire an extra memory pressure 1.174 + // event, but that's not a big deal. 1.175 + PRIntervalTime interval = PR_IntervalNow() - sLastLowMemoryNotificationTime; 1.176 + if (sHasScheduledOneLowMemoryNotification && 1.177 + PR_IntervalToMilliseconds(interval) < sLowMemoryNotificationIntervalMS) { 1.178 + 1.179 + LOG("Not scheduling low physical memory notification, " 1.180 + "because not enough time has elapsed since last one."); 1.181 + return false; 1.182 + } 1.183 + 1.184 + // There's a bit of a race condition here, since an interval may be a 1.185 + // 64-bit number, and 64-bit writes aren't atomic on x86-32. But let's 1.186 + // not worry about it -- the races only happen when we're already 1.187 + // experiencing memory pressure and firing notifications, so the worst 1.188 + // thing that can happen is that we fire two notifications when we 1.189 + // should have fired only one. 1.190 + sHasScheduledOneLowMemoryNotification = true; 1.191 + sLastLowMemoryNotificationTime = PR_IntervalNow(); 1.192 + 1.193 + LOG("Scheduling memory pressure notification."); 1.194 + NS_DispatchEventualMemoryPressure(MemPressure_New); 1.195 + return true; 1.196 +} 1.197 + 1.198 +void CheckMemAvailable() 1.199 +{ 1.200 + if (!sHooksActive) { 1.201 + return; 1.202 + } 1.203 + 1.204 + MEMORYSTATUSEX stat; 1.205 + stat.dwLength = sizeof(stat); 1.206 + bool success = GlobalMemoryStatusEx(&stat); 1.207 + 1.208 + DEBUG_WARN_IF_FALSE(success, "GlobalMemoryStatusEx failed."); 1.209 + 1.210 + if (success) 1.211 + { 1.212 + // sLowVirtualMemoryThreshold is in MB, but ullAvailVirtual is in bytes. 1.213 + if (stat.ullAvailVirtual < sLowVirtualMemoryThreshold * 1024 * 1024) { 1.214 + // If we're running low on virtual memory, unconditionally schedule the 1.215 + // notification. We'll probably crash if we run out of virtual memory, 1.216 + // so don't worry about firing this notification too often. 1.217 + LOG("Detected low virtual memory."); 1.218 + ++sNumLowVirtualMemEvents; 1.219 + NS_DispatchEventualMemoryPressure(MemPressure_New); 1.220 + } 1.221 + else if (stat.ullAvailPageFile < sLowCommitSpaceThreshold * 1024 * 1024) { 1.222 + LOG("Detected low available page file space."); 1.223 + if (MaybeScheduleMemoryPressureEvent()) { 1.224 + ++sNumLowCommitSpaceEvents; 1.225 + } 1.226 + } 1.227 + else if (stat.ullAvailPhys < sLowPhysicalMemoryThreshold * 1024 * 1024) { 1.228 + LOG("Detected low physical memory."); 1.229 + if (MaybeScheduleMemoryPressureEvent()) { 1.230 + ++sNumLowPhysicalMemEvents; 1.231 + } 1.232 + } 1.233 + } 1.234 +} 1.235 + 1.236 +LPVOID WINAPI 1.237 +VirtualAllocHook(LPVOID aAddress, SIZE_T aSize, 1.238 + DWORD aAllocationType, 1.239 + DWORD aProtect) 1.240 +{ 1.241 + // It's tempting to see whether we have enough free virtual address space for 1.242 + // this allocation and, if we don't, synchronously fire a low-memory 1.243 + // notification to free some before we allocate. 1.244 + // 1.245 + // Unfortunately that doesn't work, principally because code doesn't expect a 1.246 + // call to malloc could trigger a GC (or call into the other routines which 1.247 + // are triggered by a low-memory notification). 1.248 + // 1.249 + // I think the best we can do here is try to allocate the memory and check 1.250 + // afterwards how much free virtual address space we have. If we're running 1.251 + // low, we schedule a low-memory notification to run as soon as possible. 1.252 + 1.253 + LPVOID result = sVirtualAllocOrig(aAddress, aSize, aAllocationType, aProtect); 1.254 + 1.255 + // Don't call CheckMemAvailable for MEM_RESERVE if we're not tracking low 1.256 + // virtual memory. Similarly, don't call CheckMemAvailable for MEM_COMMIT if 1.257 + // we're not tracking low physical memory. 1.258 + if ((sLowVirtualMemoryThreshold != 0 && aAllocationType & MEM_RESERVE) || 1.259 + (sLowPhysicalMemoryThreshold != 0 && aAllocationType & MEM_COMMIT)) { 1.260 + LOG3("VirtualAllocHook(size=", aSize, ")"); 1.261 + CheckMemAvailable(); 1.262 + } 1.263 + 1.264 + return result; 1.265 +} 1.266 + 1.267 +LPVOID WINAPI 1.268 +MapViewOfFileHook(HANDLE aFileMappingObject, 1.269 + DWORD aDesiredAccess, 1.270 + DWORD aFileOffsetHigh, 1.271 + DWORD aFileOffsetLow, 1.272 + SIZE_T aNumBytesToMap) 1.273 +{ 1.274 + LPVOID result = sMapViewOfFileOrig(aFileMappingObject, aDesiredAccess, 1.275 + aFileOffsetHigh, aFileOffsetLow, 1.276 + aNumBytesToMap); 1.277 + LOG("MapViewOfFileHook"); 1.278 + CheckMemAvailable(); 1.279 + return result; 1.280 +} 1.281 + 1.282 +HBITMAP WINAPI 1.283 +CreateDIBSectionHook(HDC aDC, 1.284 + const BITMAPINFO *aBitmapInfo, 1.285 + UINT aUsage, 1.286 + VOID **aBits, 1.287 + HANDLE aSection, 1.288 + DWORD aOffset) 1.289 +{ 1.290 + // There are a lot of calls to CreateDIBSection, so we make some effort not 1.291 + // to CheckMemAvailable() for calls to CreateDIBSection which allocate only 1.292 + // a small amount of memory. 1.293 + 1.294 + // If aSection is non-null, CreateDIBSection won't allocate any new memory. 1.295 + bool doCheck = false; 1.296 + if (sHooksActive && !aSection && aBitmapInfo) { 1.297 + uint16_t bitCount = aBitmapInfo->bmiHeader.biBitCount; 1.298 + if (bitCount == 0) { 1.299 + // MSDN says bitCount == 0 means that it figures out how many bits each 1.300 + // pixel gets by examining the corresponding JPEG or PNG data. We'll just 1.301 + // assume the worst. 1.302 + bitCount = 32; 1.303 + } 1.304 + 1.305 + // |size| contains the expected allocation size in *bits*. Height may be 1.306 + // negative (indicating the direction the DIB is drawn in), so we take the 1.307 + // absolute value. 1.308 + int64_t size = bitCount * aBitmapInfo->bmiHeader.biWidth * 1.309 + aBitmapInfo->bmiHeader.biHeight; 1.310 + if (size < 0) 1.311 + size *= -1; 1.312 + 1.313 + // If we're allocating more than 1MB, check how much memory is left after 1.314 + // the allocation. 1.315 + if (size > 1024 * 1024 * 8) { 1.316 + LOG3("CreateDIBSectionHook: Large allocation (size=", size, ")"); 1.317 + doCheck = true; 1.318 + } 1.319 + } 1.320 + 1.321 + HBITMAP result = sCreateDIBSectionOrig(aDC, aBitmapInfo, aUsage, aBits, 1.322 + aSection, aOffset); 1.323 + 1.324 + if (doCheck) { 1.325 + CheckMemAvailable(); 1.326 + } 1.327 + 1.328 + return result; 1.329 +} 1.330 + 1.331 +static int64_t 1.332 +LowMemoryEventsVirtualDistinguishedAmount() 1.333 +{ 1.334 + return sNumLowVirtualMemEvents; 1.335 +} 1.336 + 1.337 +static int64_t 1.338 +LowMemoryEventsPhysicalDistinguishedAmount() 1.339 +{ 1.340 + return sNumLowPhysicalMemEvents; 1.341 +} 1.342 + 1.343 +class LowEventsReporter MOZ_FINAL : public nsIMemoryReporter 1.344 +{ 1.345 +public: 1.346 + NS_DECL_ISUPPORTS 1.347 + 1.348 + NS_IMETHOD CollectReports(nsIHandleReportCallback* aHandleReport, 1.349 + nsISupports* aData) 1.350 + { 1.351 + nsresult rv; 1.352 + 1.353 + // We only do virtual-memory tracking on 32-bit builds. 1.354 + if (sizeof(void*) == 4) { 1.355 + rv = MOZ_COLLECT_REPORT( 1.356 + "low-memory-events/virtual", KIND_OTHER, UNITS_COUNT_CUMULATIVE, 1.357 + LowMemoryEventsVirtualDistinguishedAmount(), 1.358 +"Number of low-virtual-memory events fired since startup. We fire such an " 1.359 +"event if we notice there is less than memory.low_virtual_mem_threshold_mb of " 1.360 +"virtual address space available (if zero, this behavior is disabled). The " 1.361 +"process will probably crash if it runs out of virtual address space, so " 1.362 +"this event is dire."); 1.363 + NS_ENSURE_SUCCESS(rv, rv); 1.364 + } 1.365 + 1.366 + rv = MOZ_COLLECT_REPORT( 1.367 + "low-commit-space-events", KIND_OTHER, UNITS_COUNT_CUMULATIVE, 1.368 + sNumLowCommitSpaceEvents, 1.369 +"Number of low-commit-space events fired since startup. We fire such an " 1.370 +"event if we notice there is less than memory.low_commit_space_threshold_mb of " 1.371 +"commit space available (if zero, this behavior is disabled). Windows will " 1.372 +"likely kill the process if it runs out of commit space, so this event is " 1.373 +"dire."); 1.374 + NS_ENSURE_SUCCESS(rv, rv); 1.375 + 1.376 + rv = MOZ_COLLECT_REPORT( 1.377 + "low-memory-events/physical", KIND_OTHER, UNITS_COUNT_CUMULATIVE, 1.378 + LowMemoryEventsPhysicalDistinguishedAmount(), 1.379 +"Number of low-physical-memory events fired since startup. We fire such an " 1.380 +"event if we notice there is less than memory.low_physical_memory_threshold_mb " 1.381 +"of physical memory available (if zero, this behavior is disabled). The " 1.382 +"machine will start to page if it runs out of physical memory. This may " 1.383 +"cause it to run slowly, but it shouldn't cause it to crash."); 1.384 + NS_ENSURE_SUCCESS(rv, rv); 1.385 + 1.386 + return NS_OK; 1.387 + } 1.388 +}; 1.389 +NS_IMPL_ISUPPORTS(LowEventsReporter, nsIMemoryReporter) 1.390 + 1.391 +#endif // defined(XP_WIN) 1.392 + 1.393 +/** 1.394 + * This runnable is executed in response to a memory-pressure event; we spin 1.395 + * the event-loop when receiving the memory-pressure event in the hope that 1.396 + * other observers will synchronously free some memory that we'll be able to 1.397 + * purge here. 1.398 + */ 1.399 +class nsJemallocFreeDirtyPagesRunnable MOZ_FINAL : public nsIRunnable 1.400 +{ 1.401 +public: 1.402 + NS_DECL_ISUPPORTS 1.403 + NS_DECL_NSIRUNNABLE 1.404 +}; 1.405 + 1.406 +NS_IMPL_ISUPPORTS(nsJemallocFreeDirtyPagesRunnable, nsIRunnable) 1.407 + 1.408 +NS_IMETHODIMP 1.409 +nsJemallocFreeDirtyPagesRunnable::Run() 1.410 +{ 1.411 + MOZ_ASSERT(NS_IsMainThread()); 1.412 + 1.413 +#if defined(MOZ_MEMORY) 1.414 + jemalloc_free_dirty_pages(); 1.415 +#endif 1.416 + 1.417 + return NS_OK; 1.418 +} 1.419 + 1.420 +/** 1.421 + * The memory pressure watcher is used for listening to memory-pressure events 1.422 + * and reacting upon them. We use one instance per process currently only for 1.423 + * cleaning up dirty unused pages held by jemalloc. 1.424 + */ 1.425 +class nsMemoryPressureWatcher MOZ_FINAL : public nsIObserver 1.426 +{ 1.427 +public: 1.428 + NS_DECL_ISUPPORTS 1.429 + NS_DECL_NSIOBSERVER 1.430 + 1.431 + void Init(); 1.432 + 1.433 +private: 1.434 + static bool sFreeDirtyPages; 1.435 +}; 1.436 + 1.437 +NS_IMPL_ISUPPORTS(nsMemoryPressureWatcher, nsIObserver) 1.438 + 1.439 +bool nsMemoryPressureWatcher::sFreeDirtyPages = false; 1.440 + 1.441 +/** 1.442 + * Initialize and subscribe to the memory-pressure events. We subscribe to the 1.443 + * observer service in this method and not in the constructor because we need 1.444 + * to hold a strong reference to 'this' before calling the observer service. 1.445 + */ 1.446 +void 1.447 +nsMemoryPressureWatcher::Init() 1.448 +{ 1.449 + nsCOMPtr<nsIObserverService> os = services::GetObserverService(); 1.450 + 1.451 + if (os) { 1.452 + os->AddObserver(this, "memory-pressure", /* ownsWeak */ false); 1.453 + } 1.454 + 1.455 + Preferences::AddBoolVarCache(&sFreeDirtyPages, "memory.free_dirty_pages", 1.456 + false); 1.457 +} 1.458 + 1.459 +/** 1.460 + * Reacts to all types of memory-pressure events, launches a runnable to 1.461 + * free dirty pages held by jemalloc. 1.462 + */ 1.463 +NS_IMETHODIMP 1.464 +nsMemoryPressureWatcher::Observe(nsISupports *subject, const char *topic, 1.465 + const char16_t *data) 1.466 +{ 1.467 + MOZ_ASSERT(!strcmp(topic, "memory-pressure"), "Unknown topic"); 1.468 + 1.469 + if (sFreeDirtyPages) { 1.470 + nsRefPtr<nsIRunnable> runnable = new nsJemallocFreeDirtyPagesRunnable(); 1.471 + 1.472 + NS_DispatchToMainThread(runnable); 1.473 + } 1.474 + 1.475 + return NS_OK; 1.476 +} 1.477 + 1.478 +} // anonymous namespace 1.479 + 1.480 +namespace mozilla { 1.481 +namespace AvailableMemoryTracker { 1.482 + 1.483 +void Activate() 1.484 +{ 1.485 +#if defined(_M_IX86) && defined(XP_WIN) 1.486 + MOZ_ASSERT(sInitialized); 1.487 + MOZ_ASSERT(!sHooksActive); 1.488 + 1.489 + // On 64-bit systems, hardcode sLowVirtualMemoryThreshold to 0 -- we assume 1.490 + // we're not going to run out of virtual memory! 1.491 + if (sizeof(void*) > 4) { 1.492 + sLowVirtualMemoryThreshold = 0; 1.493 + } 1.494 + else { 1.495 + Preferences::AddUintVarCache(&sLowVirtualMemoryThreshold, 1.496 + "memory.low_virtual_mem_threshold_mb", 128); 1.497 + } 1.498 + 1.499 + Preferences::AddUintVarCache(&sLowPhysicalMemoryThreshold, 1.500 + "memory.low_physical_memory_threshold_mb", 0); 1.501 + Preferences::AddUintVarCache(&sLowCommitSpaceThreshold, 1.502 + "memory.low_commit_space_threshold_mb", 128); 1.503 + Preferences::AddUintVarCache(&sLowMemoryNotificationIntervalMS, 1.504 + "memory.low_memory_notification_interval_ms", 10000); 1.505 + 1.506 + RegisterStrongMemoryReporter(new LowEventsReporter()); 1.507 + RegisterLowMemoryEventsVirtualDistinguishedAmount(LowMemoryEventsVirtualDistinguishedAmount); 1.508 + RegisterLowMemoryEventsPhysicalDistinguishedAmount(LowMemoryEventsPhysicalDistinguishedAmount); 1.509 + sHooksActive = true; 1.510 +#endif 1.511 + 1.512 + // This object is held alive by the observer service. 1.513 + nsRefPtr<nsMemoryPressureWatcher> watcher = new nsMemoryPressureWatcher(); 1.514 + watcher->Init(); 1.515 +} 1.516 + 1.517 +void Init() 1.518 +{ 1.519 + // Do nothing on x86-64, because nsWindowsDllInterceptor is not thread-safe 1.520 + // on 64-bit. (On 32-bit, it's probably thread-safe.) Even if we run Init() 1.521 + // before any other of our threads are running, another process may have 1.522 + // started a remote thread which could call VirtualAlloc! 1.523 + // 1.524 + // Moreover, the benefit of this code is less clear when we're a 64-bit 1.525 + // process, because we aren't going to run out of virtual memory, and the 1.526 + // system is likely to have a fair bit of physical memory. 1.527 + 1.528 +#if defined(_M_IX86) && defined(XP_WIN) 1.529 + // Don't register the hooks if we're a build instrumented for PGO: If we're 1.530 + // an instrumented build, the compiler adds function calls all over the place 1.531 + // which may call VirtualAlloc; this makes it hard to prevent 1.532 + // VirtualAllocHook from reentering itself. 1.533 + if (!PR_GetEnv("MOZ_PGO_INSTRUMENTED")) { 1.534 + sKernel32Intercept.Init("Kernel32.dll"); 1.535 + sKernel32Intercept.AddHook("VirtualAlloc", 1.536 + reinterpret_cast<intptr_t>(VirtualAllocHook), 1.537 + (void**) &sVirtualAllocOrig); 1.538 + sKernel32Intercept.AddHook("MapViewOfFile", 1.539 + reinterpret_cast<intptr_t>(MapViewOfFileHook), 1.540 + (void**) &sMapViewOfFileOrig); 1.541 + 1.542 + sGdi32Intercept.Init("Gdi32.dll"); 1.543 + sGdi32Intercept.AddHook("CreateDIBSection", 1.544 + reinterpret_cast<intptr_t>(CreateDIBSectionHook), 1.545 + (void**) &sCreateDIBSectionOrig); 1.546 + } 1.547 + 1.548 + sInitialized = true; 1.549 +#endif 1.550 +} 1.551 + 1.552 +} // namespace AvailableMemoryTracker 1.553 +} // namespace mozilla