1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /*
8  * JS allocation policies.
9  *
10  * The allocators here are for system memory with lifetimes which are not
11  * managed by the GC. See the comment at the top of vm/MallocProvider.h.
12  */
13 
14 #ifndef jsalloc_h
15 #define jsalloc_h
16 
17 #include "js/TypeDecls.h"
18 #include "js/Utility.h"
19 
20 namespace js {
21 
22 enum class AllocFunction {
23     Malloc,
24     Calloc,
25     Realloc
26 };
27 
28 struct ContextFriendFields;
29 
30 /* Policy for using system memory functions and doing no error reporting. */
31 class SystemAllocPolicy
32 {
33   public:
maybe_pod_malloc(size_t numElems)34     template <typename T> T* maybe_pod_malloc(size_t numElems) { return js_pod_malloc<T>(numElems); }
maybe_pod_calloc(size_t numElems)35     template <typename T> T* maybe_pod_calloc(size_t numElems) { return js_pod_calloc<T>(numElems); }
maybe_pod_realloc(T * p,size_t oldSize,size_t newSize)36     template <typename T> T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
37         return js_pod_realloc<T>(p, oldSize, newSize);
38     }
pod_malloc(size_t numElems)39     template <typename T> T* pod_malloc(size_t numElems) { return maybe_pod_malloc<T>(numElems); }
pod_calloc(size_t numElems)40     template <typename T> T* pod_calloc(size_t numElems) { return maybe_pod_calloc<T>(numElems); }
pod_realloc(T * p,size_t oldSize,size_t newSize)41     template <typename T> T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
42         return maybe_pod_realloc<T>(p, oldSize, newSize);
43     }
free_(void * p)44     void free_(void* p) { js_free(p); }
reportAllocOverflow()45     void reportAllocOverflow() const {}
checkSimulatedOOM()46     bool checkSimulatedOOM() const {
47         return !js::oom::ShouldFailWithOOM();
48     }
49 };
50 
51 class ExclusiveContext;
52 void ReportOutOfMemory(ExclusiveContext* cxArg);
53 
54 /*
55  * Allocation policy that calls the system memory functions and reports errors
56  * to the context. Since the JSContext given on construction is stored for
57  * the lifetime of the container, this policy may only be used for containers
58  * whose lifetime is a shorter than the given JSContext.
59  *
60  * FIXME bug 647103 - rewrite this in terms of temporary allocation functions,
61  * not the system ones.
62  */
63 class TempAllocPolicy
64 {
65     ContextFriendFields* const cx_;
66 
67     /*
68      * Non-inline helper to call JSRuntime::onOutOfMemory with minimal
69      * code bloat.
70      */
71     JS_FRIEND_API(void*) onOutOfMemory(AllocFunction allocFunc, size_t nbytes,
72                                        void* reallocPtr = nullptr);
73 
74     template <typename T>
75     T* onOutOfMemoryTyped(AllocFunction allocFunc, size_t numElems, void* reallocPtr = nullptr) {
76         size_t bytes;
77         if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes)))
78             return nullptr;
79         return static_cast<T*>(onOutOfMemory(allocFunc, bytes, reallocPtr));
80     }
81 
82   public:
TempAllocPolicy(JSContext * cx)83     MOZ_IMPLICIT TempAllocPolicy(JSContext* cx) : cx_((ContextFriendFields*) cx) {} // :(
TempAllocPolicy(ContextFriendFields * cx)84     MOZ_IMPLICIT TempAllocPolicy(ContextFriendFields* cx) : cx_(cx) {}
85 
86     template <typename T>
maybe_pod_malloc(size_t numElems)87     T* maybe_pod_malloc(size_t numElems) {
88         return js_pod_malloc<T>(numElems);
89     }
90 
91     template <typename T>
maybe_pod_calloc(size_t numElems)92     T* maybe_pod_calloc(size_t numElems) {
93         return js_pod_calloc<T>(numElems);
94     }
95 
96     template <typename T>
maybe_pod_realloc(T * prior,size_t oldSize,size_t newSize)97     T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) {
98         return js_pod_realloc<T>(prior, oldSize, newSize);
99     }
100 
101     template <typename T>
pod_malloc(size_t numElems)102     T* pod_malloc(size_t numElems) {
103         T* p = maybe_pod_malloc<T>(numElems);
104         if (MOZ_UNLIKELY(!p))
105             p = onOutOfMemoryTyped<T>(AllocFunction::Malloc, numElems);
106         return p;
107     }
108 
109     template <typename T>
pod_calloc(size_t numElems)110     T* pod_calloc(size_t numElems) {
111         T* p = maybe_pod_calloc<T>(numElems);
112         if (MOZ_UNLIKELY(!p))
113             p = onOutOfMemoryTyped<T>(AllocFunction::Calloc, numElems);
114         return p;
115     }
116 
117     template <typename T>
pod_realloc(T * prior,size_t oldSize,size_t newSize)118     T* pod_realloc(T* prior, size_t oldSize, size_t newSize) {
119         T* p2 = maybe_pod_realloc<T>(prior, oldSize, newSize);
120         if (MOZ_UNLIKELY(!p2))
121             p2 = onOutOfMemoryTyped<T>(AllocFunction::Realloc, newSize, prior);
122         return p2;
123     }
124 
free_(void * p)125     void free_(void* p) {
126         js_free(p);
127     }
128 
129     JS_FRIEND_API(void) reportAllocOverflow() const;
130 
checkSimulatedOOM()131     bool checkSimulatedOOM() const {
132         if (js::oom::ShouldFailWithOOM()) {
133             js::ReportOutOfMemory(reinterpret_cast<ExclusiveContext*>(cx_));
134             return false;
135         }
136 
137         return true;
138     }
139 };
140 
141 } /* namespace js */
142 
143 #endif /* jsalloc_h */
144