OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stddef.h> | 5 #include <stddef.h> |
6 #include <stdlib.h> | 6 #include <stdlib.h> |
7 | 7 |
8 #include "base/process/memory.h" | 8 #include "base/process/memory.h" |
9 #include "build/build_config.h" | 9 #include "build/build_config.h" |
| 10 #include "skia_memory_dump_provider.h" |
10 #include "third_party/skia/include/core/SkTypes.h" | 11 #include "third_party/skia/include/core/SkTypes.h" |
11 | 12 |
12 // This implementation of sk_malloc_flags() and friends is similar to | 13 // This implementation of sk_malloc_flags() and friends is similar to |
13 // SkMemory_malloc.cpp, except it uses base::UncheckedMalloc and friends | 14 // SkMemory_malloc.cpp, except it uses base::UncheckedMalloc and friends |
14 // for non-SK_MALLOC_THROW calls. | 15 // for non-SK_MALLOC_THROW calls. |
15 // | 16 // |
16 // The name of this file is historic: a previous implementation tried to | 17 // The name of this file is historic: a previous implementation tried to |
17 // use std::set_new_handler() for the same effect, but it didn't actually work. | 18 // use std::set_new_handler() for the same effect, but it didn't actually work. |
18 | 19 |
19 static inline void* throw_on_failure(size_t size, void* p) { | 20 static inline void* throw_on_failure(size_t size, void* p) { |
20 if (size > 0 && p == NULL) { | 21 if (size > 0 && p == NULL) { |
21 // If we've got a NULL here, the only reason we should have failed is ru
nning out of RAM. | 22 // If we've got a NULL here, the only reason we should have failed is ru
nning out of RAM. |
22 sk_out_of_memory(); | 23 sk_out_of_memory(); |
23 } | 24 } |
24 return p; | 25 return p; |
25 } | 26 } |
26 | 27 |
27 void sk_abort_no_print() { | 28 void sk_abort_no_print() { |
28 abort(); | 29 abort(); |
29 } | 30 } |
30 | 31 |
31 void sk_out_of_memory(void) { | 32 void sk_out_of_memory(void) { |
32 SkASSERT(!"sk_out_of_memory"); | 33 SkASSERT(!"sk_out_of_memory"); |
33 abort(); | 34 abort(); |
34 } | 35 } |
35 | 36 |
36 void* sk_realloc_throw(void* addr, size_t size) { | 37 void* sk_realloc_throw(void* addr, size_t size, const char* typeName) { |
37 return throw_on_failure(size, realloc(addr, size)); | 38 skia::SkiaAllocHooks::FreeHookIfEnabled(addr); |
| 39 void* new_address = realloc(addr, size); |
| 40 skia::SkiaAllocHooks::AllocationHookIfEnabled(new_address, size, typeName); |
| 41 return throw_on_failure(size, new_address); |
38 } | 42 } |
39 | 43 |
40 void sk_free(void* p) { | 44 void sk_free(void* p) { |
41 if (p) { | 45 if (p) { |
| 46 skia::SkiaAllocHooks::FreeHookIfEnabled(p); |
42 free(p); | 47 free(p); |
43 } | 48 } |
44 } | 49 } |
45 | 50 |
46 // We get lots of bugs filed on us that amount to overcommiting bitmap memory, | 51 // We get lots of bugs filed on us that amount to overcommiting bitmap memory, |
47 // then some time later failing to back that VM with physical memory. | 52 // then some time later failing to back that VM with physical memory. |
48 // They're hard to track down, so in Debug mode we touch all memory right up fro
nt. | 53 // They're hard to track down, so in Debug mode we touch all memory right up fro
nt. |
49 // | 54 // |
50 // For malloc, fill is an arbitrary byte and ideally not 0. For calloc, it's go
t to be 0. | 55 // For malloc, fill is an arbitrary byte and ideally not 0. For calloc, it's go
t to be 0. |
51 static void* prevent_overcommit(int fill, size_t size, void* p) { | 56 static void* prevent_overcommit(int fill, size_t size, void* p) { |
52 // We probably only need to touch one byte per page, but memset makes things
easy. | 57 // We probably only need to touch one byte per page, but memset makes things
easy. |
53 SkDEBUGCODE(memset(p, fill, size)); | 58 SkDEBUGCODE(memset(p, fill, size)); |
54 return p; | 59 return p; |
55 } | 60 } |
56 | 61 |
57 void* sk_malloc_throw(size_t size) { | 62 void* sk_malloc_throw(size_t size, const char* typeName) { |
58 return prevent_overcommit(0x42, size, throw_on_failure(size, malloc(size))); | 63 void* address = throw_on_failure(size, malloc(size)); |
| 64 skia::SkiaAllocHooks::AllocationHookIfEnabled(address, size, typeName); |
| 65 return prevent_overcommit(0x42, size, address); |
59 } | 66 } |
60 | 67 |
61 static void* sk_malloc_nothrow(size_t size) { | 68 static void* sk_malloc_nothrow(size_t size, const char* typeName) { |
62 // TODO(b.kelemen): we should always use UncheckedMalloc but currently it | 69 // TODO(b.kelemen): we should always use UncheckedMalloc but currently it |
63 // doesn't work as intended everywhere. | 70 // doesn't work as intended everywhere. |
64 void* result; | 71 void* result; |
65 #if defined(OS_IOS) | 72 #if defined(OS_IOS) |
66 result = malloc(size); | 73 result = malloc(size); |
67 #else | 74 #else |
68 // It's the responsibility of the caller to check the return value. | 75 // It's the responsibility of the caller to check the return value. |
69 ignore_result(base::UncheckedMalloc(size, &result)); | 76 ignore_result(base::UncheckedMalloc(size, &result)); |
70 #endif | 77 #endif |
71 if (result) { | 78 if (result) { |
72 prevent_overcommit(0x47, size, result); | 79 prevent_overcommit(0x47, size, result); |
73 } | 80 } |
| 81 skia::SkiaAllocHooks::AllocationHookIfEnabled(result, size, typeName); |
74 return result; | 82 return result; |
75 } | 83 } |
76 | 84 |
77 void* sk_malloc_flags(size_t size, unsigned flags) { | 85 void* sk_malloc_flags(size_t size, unsigned flags, const char* typeName) { |
78 if (flags & SK_MALLOC_THROW) { | 86 if (flags & SK_MALLOC_THROW) { |
79 return sk_malloc_throw(size); | 87 return sk_malloc_throw(size, typeName); |
80 } | 88 } |
81 return sk_malloc_nothrow(size); | 89 return sk_malloc_nothrow(size, typeName); |
82 } | 90 } |
83 | 91 |
84 void* sk_calloc_throw(size_t size) { | 92 void* sk_calloc_throw(size_t size, const char* typeName) { |
85 return prevent_overcommit(0, size, throw_on_failure(size, calloc(size, 1))); | 93 void* address = calloc(size, 1); |
| 94 skia::SkiaAllocHooks::AllocationHookIfEnabled(address, size, typeName); |
| 95 return prevent_overcommit(0, size, throw_on_failure(size, address)); |
86 } | 96 } |
87 | 97 |
88 void* sk_calloc(size_t size) { | 98 void* sk_calloc(size_t size, const char* typeName) { |
89 // TODO(b.kelemen): we should always use UncheckedCalloc but currently it | 99 // TODO(b.kelemen): we should always use UncheckedCalloc but currently it |
90 // doesn't work as intended everywhere. | 100 // doesn't work as intended everywhere. |
91 void* result; | 101 void* result; |
92 #if defined(OS_IOS) | 102 #if defined(OS_IOS) |
93 result = calloc(1, size); | 103 result = calloc(1, size); |
94 #else | 104 #else |
95 // It's the responsibility of the caller to check the return value. | 105 // It's the responsibility of the caller to check the return value. |
96 ignore_result(base::UncheckedCalloc(size, 1, &result)); | 106 ignore_result(base::UncheckedCalloc(size, 1, &result)); |
97 #endif | 107 #endif |
98 if (result) { | 108 if (result) { |
99 prevent_overcommit(0, size, result); | 109 prevent_overcommit(0, size, result); |
100 } | 110 } |
| 111 skia::SkiaAllocHooks::AllocationHookIfEnabled(result, size, typeName); |
101 return result; | 112 return result; |
102 } | 113 } |
OLD | NEW |