| OLD | NEW |
| 1 // Copyright (c) 2011, Google Inc. | 1 // Copyright (c) 2011, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 // For both types of lists: when a pop operation is performed on a non | 55 // For both types of lists: when a pop operation is performed on a non |
| 56 // empty list, the new list head becomes that which is pointed to by | 56 // empty list, the new list head becomes that which is pointed to by |
| 57 // the former head's |next| pointer. If the list is doubly linked, the | 57 // the former head's |next| pointer. If the list is doubly linked, the |
| 58 // new head |previous| pointer gets changed from pointing to the former | 58 // new head |previous| pointer gets changed from pointing to the former |
| 59 // head to NULL. | 59 // head to NULL. |
| 60 | 60 |
| 61 | 61 |
| 62 #include <limits> | 62 #include <limits> |
| 63 #include <stddef.h> | 63 #include <stddef.h> |
| 64 #include "free_list.h" | 64 #include "free_list.h" |
| 65 #include "system-alloc.h" | |
| 66 | 65 |
| 67 #if defined(TCMALLOC_USE_DOUBLYLINKED_FREELIST) | 66 #if defined(TCMALLOC_USE_DOUBLYLINKED_FREELIST) |
| 68 | 67 |
| 69 using tcmalloc::kCrash; | |
| 70 | |
| 71 // TODO(jar): We should use C++ rather than a macro here. | |
| 72 #define MEMORY_CHECK(v1, v2) \ | |
| 73 if (v1 != v2) Log(kCrash, __FILE__, __LINE__, "Memory corruption detected.") | |
| 74 | |
| 75 namespace { | |
| 76 void EnsureNonLoop(void* node, void* next) { | |
| 77 // We only have time to do minimal checking. We don't traverse the list, but | |
| 78 // only look for an immediate loop (cycle back to ourself). | |
| 79 if (node != next) return; | |
| 80 Log(kCrash, __FILE__, __LINE__, "Circular loop in list detected: ", next); | |
| 81 } | |
| 82 | |
| 83 inline void* MaskPtr(void* p) { | |
| 84 // Maximize ASLR entropy and guarantee the result is an invalid address. | |
| 85 const uintptr_t mask = ~(reinterpret_cast<uintptr_t>(TCMalloc_SystemAlloc) | |
| 86 >> 13); | |
| 87 return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) ^ mask); | |
| 88 } | |
| 89 | |
| 90 inline void* UnmaskPtr(void* p) { | |
| 91 return MaskPtr(p); | |
| 92 } | |
| 93 | |
| 94 // Returns value of the |previous| pointer w/out running a sanity | |
| 95 // check. | |
| 96 inline void *FL_Previous_No_Check(void *t) { | |
| 97 return UnmaskPtr(reinterpret_cast<void**>(t)[1]); | |
| 98 } | |
| 99 | |
| 100 // Returns value of the |next| pointer w/out running a sanity check. | |
| 101 inline void *FL_Next_No_Check(void *t) { | |
| 102 return UnmaskPtr(reinterpret_cast<void**>(t)[0]); | |
| 103 } | |
| 104 | |
| 105 void *FL_Previous(void *t) { | |
| 106 void *previous = FL_Previous_No_Check(t); | |
| 107 if (previous) { | |
| 108 MEMORY_CHECK(FL_Next_No_Check(previous), t); | |
| 109 } | |
| 110 return previous; | |
| 111 } | |
| 112 | |
| 113 inline void FL_SetPrevious(void *t, void *n) { | |
| 114 EnsureNonLoop(t, n); | |
| 115 reinterpret_cast<void**>(t)[1] = MaskPtr(n); | |
| 116 } | |
| 117 | |
| 118 inline void FL_SetNext(void *t, void *n) { | |
| 119 EnsureNonLoop(t, n); | |
| 120 reinterpret_cast<void**>(t)[0] = MaskPtr(n); | |
| 121 } | |
| 122 | |
| 123 } // namespace | |
| 124 | |
| 125 namespace tcmalloc { | 68 namespace tcmalloc { |
| 126 | 69 |
| 127 void *FL_Next(void *t) { | |
| 128 void *next = FL_Next_No_Check(t); | |
| 129 if (next) { | |
| 130 MEMORY_CHECK(FL_Previous_No_Check(next), t); | |
| 131 } | |
| 132 return next; | |
| 133 } | |
| 134 | |
| 135 // Makes the element at |t| a singleton doubly linked list. | |
| 136 void FL_Init(void *t) { | |
| 137 FL_SetPrevious(t, NULL); | |
| 138 FL_SetNext(t, NULL); | |
| 139 } | |
| 140 | |
| 141 // Pushes element to a linked list whose first element is at | |
| 142 // |*list|. When this call returns, |list| will point to the new head | |
| 143 // of the linked list. | |
| 144 void FL_Push(void **list, void *element) { | |
| 145 void *old = *list; | |
| 146 if (old == NULL) { // Builds singleton list. | |
| 147 FL_Init(element); | |
| 148 } else { | |
| 149 ASSERT(FL_Previous_No_Check(old) == NULL); | |
| 150 FL_SetNext(element, old); | |
| 151 FL_SetPrevious(old, element); | |
| 152 FL_SetPrevious(element, NULL); | |
| 153 } | |
| 154 *list = element; | |
| 155 } | |
| 156 | |
| 157 // Pops the top element off the linked list whose first element is at | |
| 158 // |*list|, and updates |*list| to point to the next element in the | |
| 159 // list. Returns the address of the element that was removed from the | |
| 160 // linked list. |list| must not be NULL. | |
| 161 void *FL_Pop(void **list) { | |
| 162 void *result = *list; | |
| 163 ASSERT(FL_Previous_No_Check(result) == NULL); | |
| 164 *list = FL_Next(result); | |
| 165 if (*list != NULL) { | |
| 166 FL_SetPrevious(*list, NULL); | |
| 167 } | |
| 168 return result; | |
| 169 } | |
| 170 | |
| 171 // Remove |n| elements from linked list at whose first element is at | 70 // Remove |n| elements from linked list at whose first element is at |
| 172 // |*head|. |head| will be modified to point to the new head. | 71 // |*head|. |head| will be modified to point to the new head. |
| 173 // |start| will point to the first node of the range, |end| will point | 72 // |start| will point to the first node of the range, |end| will point |
| 174 // to the last node in the range. |n| must be <= FL_Size(|*head|) | 73 // to the last node in the range. |n| must be <= FL_Size(|*head|) |
| 175 // If |n| > 0, |head| must not be NULL. | 74 // If |n| > 0, |head| must not be NULL. |
| 176 void FL_PopRange(void **head, int n, void **start, void **end) { | 75 void FL_PopRange(void **head, int n, void **start, void **end) { |
| 177 if (n == 0) { | 76 if (n == 0) { |
| 178 *start = NULL; | 77 *start = NULL; |
| 179 *end = NULL; | 78 *end = NULL; |
| 180 return; | 79 return; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 201 if (!start) return; | 100 if (!start) return; |
| 202 | 101 |
| 203 // Sanity checking of ends of list to push is done by calling | 102 // Sanity checking of ends of list to push is done by calling |
| 204 // FL_Next and FL_Previous. | 103 // FL_Next and FL_Previous. |
| 205 FL_Next(start); | 104 FL_Next(start); |
| 206 FL_Previous(end); | 105 FL_Previous(end); |
| 207 ASSERT(FL_Previous_No_Check(start) == NULL); | 106 ASSERT(FL_Previous_No_Check(start) == NULL); |
| 208 ASSERT(FL_Next_No_Check(end) == NULL); | 107 ASSERT(FL_Next_No_Check(end) == NULL); |
| 209 | 108 |
| 210 if (*head) { | 109 if (*head) { |
| 211 MEMORY_CHECK(FL_Previous_No_Check(*head), NULL); | 110 FL_EqualityCheck(FL_Previous_No_Check(*head), (void*)NULL, |
| 111 __FILE__, __LINE__); |
| 212 FL_SetNext(end, *head); | 112 FL_SetNext(end, *head); |
| 213 FL_SetPrevious(*head, end); | 113 FL_SetPrevious(*head, end); |
| 214 } | 114 } |
| 215 *head = start; | 115 *head = start; |
| 216 } | 116 } |
| 217 | 117 |
| 218 // Calculates the size of the list that begins at |head|. | 118 // Calculates the size of the list that begins at |head|. |
| 219 size_t FL_Size(void *head){ | 119 size_t FL_Size(void *head){ |
| 220 int count = 0; | 120 int count = 0; |
| 221 if (head) { | 121 if (head) { |
| 222 MEMORY_CHECK(FL_Previous_No_Check(head), NULL); | 122 FL_EqualityCheck(FL_Previous_No_Check(head), (void*)NULL, |
| 123 __FILE__, __LINE__); |
| 223 } | 124 } |
| 224 while (head) { | 125 while (head) { |
| 225 count++; | 126 count++; |
| 226 head = FL_Next(head); | 127 head = FL_Next(head); |
| 227 } | 128 } |
| 228 return count; | 129 return count; |
| 229 } | 130 } |
| 230 | 131 |
| 231 } // namespace tcmalloc | 132 } // namespace tcmalloc |
| 232 | 133 |
| 233 #else | 134 #else |
| 234 #include "linked_list.h" // for SLL_SetNext | 135 #include "linked_list.h" // for SLL_SetNext |
| 235 | 136 |
| 236 namespace { | 137 namespace { |
| 237 | 138 |
| 238 inline void FL_SetNext(void *t, void *n) { | 139 inline void FL_SetNext(void *t, void *n) { |
| 239 tcmalloc::SLL_SetNext(t,n); | 140 tcmalloc::SLL_SetNext(t,n); |
| 240 } | 141 } |
| 241 | 142 |
| 242 } | 143 } |
| 243 | 144 |
| 244 #endif // TCMALLOC_USE_DOUBLYLINKED_FREELIST | 145 #endif // TCMALLOC_USE_DOUBLYLINKED_FREELIST |
| OLD | NEW |