| // Copyright 2015 The Cobalt Authors. All Rights Reserved. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // Module Overview: Starboard Memory module | |
| // | |
| // Defines functions for memory allocation, alignment, copying, and comparing. | |
| // | |
| // # Porters | |
| // | |
| // All of the "Unchecked" and "Free" functions must be implemented, but they | |
| // should not be called directly. The Starboard platform wraps them with extra | |
| // accounting under certain circumstances. | |
| // | |
| // # Porters and Application Developers | |
| // | |
| // Nobody should call the "Checked", "Unchecked" or "Free" functions directly | |
| // because that evades Starboard's memory tracking. In both port | |
| // implementations and Starboard client application code, you should always | |
| // call SbMemoryAllocate and SbMemoryDeallocate rather than | |
| // SbMemoryAllocateUnchecked and SbMemoryFree. | |
| // | |
| // - The "checked" functions are SbMemoryAllocateChecked(), | |
| // SbMemoryReallocateChecked(), and SbMemoryAllocateAlignedChecked(). | |
| // - The "unchecked" functions are SbMemoryAllocateUnchecked(), | |
| // SbMemoryReallocateUnchecked(), and SbMemoryAllocateAlignedUnchecked(). | |
| // - The "free" functions are SbMemoryFree() and SbMemoryFreeAligned(). | |
| #ifndef STARBOARD_MEMORY_H_ | |
| #define STARBOARD_MEMORY_H_ | |
| #include "starboard/configuration.h" | |
| #include "starboard/export.h" | |
| #include "starboard/system.h" | |
| #include "starboard/types.h" | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| #define SB_MEMORY_MAP_FAILED ((void*)-1) // NOLINT(readability/casting) | |
| // The bitwise OR of these flags should be passed to SbMemoryMap to indicate | |
| // how the mapped memory can be used. | |
| typedef enum SbMemoryMapFlags { | |
| // No flags set: Reserves virtual address space. SbMemoryProtect() can later | |
| // make it accessible. | |
| #if SB_API_VERSION >= 10 | |
| kSbMemoryMapProtectReserved = 0, | |
| #endif | |
| kSbMemoryMapProtectRead = 1 << 0, // Mapped memory can be read. | |
| kSbMemoryMapProtectWrite = 1 << 1, // Mapped memory can be written to. | |
| #if SB_CAN(MAP_EXECUTABLE_MEMORY) | |
| kSbMemoryMapProtectExec = 1 << 2, // Mapped memory can be executed. | |
| #endif | |
| kSbMemoryMapProtectReadWrite = | |
| kSbMemoryMapProtectRead | kSbMemoryMapProtectWrite, | |
| } SbMemoryMapFlags; | |
| // Checks whether |memory| is aligned to |alignment| bytes. | |
| static SB_C_FORCE_INLINE bool SbMemoryIsAligned(const void* memory, | |
| size_t alignment) { | |
| return ((uintptr_t)memory) % alignment == 0; | |
| } | |
| // Rounds |size| up to SB_MEMORY_PAGE_SIZE. | |
| static SB_C_FORCE_INLINE size_t SbMemoryAlignToPageSize(size_t size) { | |
| return (size + SB_MEMORY_PAGE_SIZE - 1) & ~(SB_MEMORY_PAGE_SIZE - 1); | |
| } | |
| static SB_C_FORCE_INLINE void SbAbortIfAllocationFailed(size_t requested_bytes, | |
| void* address) { | |
| if (SB_UNLIKELY(requested_bytes > 0 && address == NULL)) { | |
| // Will abort the program if no debugger is attached. | |
| SbSystemBreakIntoDebugger(); | |
| } | |
| } | |
| // Allocates and returns a chunk of memory of at least |size| bytes. This | |
| // function should be called from the client codebase. It is intended to be a | |
| // drop-in replacement for |malloc|. | |
| // | |
| // Note that this function returns |NULL| if it is unable to allocate the | |
| // memory. | |
| // | |
| // |size|: The amount of memory to be allocated. If |size| is 0, the function | |
| // may return |NULL| or it may return a unique pointer value that can be | |
| // passed to SbMemoryDeallocate. | |
| SB_EXPORT void* SbMemoryAllocate(size_t size); | |
| // Same as SbMemoryAllocate() but will not report memory to the tracker. Avoid | |
| // using this unless absolutely necessary. | |
| SB_EXPORT void* SbMemoryAllocateNoReport(size_t size); | |
| // Attempts to resize |memory| to be at least |size| bytes, without touching | |
| // the contents of memory. | |
| // - If the function cannot perform the fast resize, it allocates a new chunk | |
| // of memory, copies the contents over, and frees the previous chunk, | |
| // returning a pointer to the new chunk. | |
| // - If the function cannot perform the slow resize, it returns |NULL|, | |
| // leaving the given memory chunk unchanged. | |
| // | |
| // This function should be called from the client codebase. It is meant to be a | |
| // drop-in replacement for |realloc|. | |
| // | |
| // |memory|: The chunk of memory to be resized. |memory| may be NULL, in which | |
| // case it behaves exactly like SbMemoryAllocateUnchecked. | |
| // |size|: The size to which |memory| will be resized. If |size| is |0|, | |
| // the function may return |NULL| or it may return a unique pointer value | |
| // that can be passed to SbMemoryDeallocate. | |
| SB_EXPORT void* SbMemoryReallocate(void* memory, size_t size); | |
| // Allocates and returns a chunk of memory of at least |size| bytes, aligned to | |
| // |alignment|. This function should be called from the client codebase. It is | |
| // meant to be a drop-in replacement for |memalign|. | |
| // | |
| // The function returns |NULL| if it cannot allocate the memory. In addition, | |
| // the function's behavior is undefined if |alignment| is not a power of two. | |
| // | |
| // |alignment|: The way that data is arranged and accessed in memory. The value | |
| // must be a power of two. | |
| // |size|: The size of the memory to be allocated. If |size| is |0|, the | |
| // function may return |NULL| or it may return a unique aligned pointer value | |
| // that can be passed to SbMemoryDeallocateAligned. | |
| SB_EXPORT void* SbMemoryAllocateAligned(size_t alignment, size_t size); | |
| // Frees a previously allocated chunk of memory. If |memory| is NULL, then the | |
| // operation is a no-op. This function should be called from the client | |
| // codebase. It is meant to be a drop-in replacement for |free|. | |
| // | |
| // |memory|: The chunk of memory to be freed. | |
| SB_EXPORT void SbMemoryDeallocate(void* memory); | |
| // Same as SbMemoryDeallocate() but will not report memory deallocation to the | |
| // tracker. This function must be matched with SbMemoryAllocateNoReport(). | |
| SB_EXPORT void SbMemoryDeallocateNoReport(void* memory); | |
| // Frees a previously allocated chunk of aligned memory. This function should | |
| // be called from the client codebase. It is meant to be a drop-in replacement | |
| // for |_aligned_free|. | |
| // |memory|: The chunk of memory to be freed. If |memory| is NULL, then the | |
| // function is a no-op. | |
| SB_EXPORT void SbMemoryDeallocateAligned(void* memory); | |
| ///////////////////////////////////////////////////////////////// | |
| // The following functions must be provided by Starboard ports. | |
| ///////////////////////////////////////////////////////////////// | |
| // This is the implementation of SbMemoryAllocate that must be | |
| // provided by Starboard ports. | |
| // | |
| // DO NOT CALL. Call SbMemoryAllocate(...) instead. | |
| SB_DEPRECATED_EXTERNAL( | |
| SB_EXPORT void* SbMemoryAllocateUnchecked(size_t size)); | |
| // This is the implementation of SbMemoryReallocate that must be | |
| // provided by Starboard ports. | |
| // | |
| // DO NOT CALL. Call SbMemoryReallocate(...) instead. | |
| SB_DEPRECATED_EXTERNAL( | |
| SB_EXPORT void* SbMemoryReallocateUnchecked(void* memory, size_t size)); | |
| // This is the implementation of SbMemoryAllocateAligned that must be | |
| // provided by Starboard ports. | |
| // | |
| // DO NOT CALL. Call SbMemoryAllocateAligned(...) instead. | |
| SB_DEPRECATED_EXTERNAL( | |
| SB_EXPORT void* SbMemoryAllocateAlignedUnchecked(size_t alignment, | |
| size_t size)); | |
| // This is the implementation of SbMemoryDeallocate that must be provided by | |
| // Starboard ports. | |
| // | |
| // DO NOT CALL. Call SbMemoryDeallocate(...) instead. | |
| SB_DEPRECATED_EXTERNAL( | |
| SB_EXPORT void SbMemoryFree(void* memory)); | |
| // This is the implementation of SbMemoryFreeAligned that must be provided by | |
| // Starboard ports. | |
| // | |
| // DO NOT CALL. Call SbMemoryDeallocateAligned(...) instead. | |
| SB_DEPRECATED_EXTERNAL( | |
| SB_EXPORT void SbMemoryFreeAligned(void* memory)); | |
| #if SB_API_VERSION >= SB_MMAP_REQUIRED_VERSION || SB_HAS(MMAP) | |
| // Allocates |size_bytes| worth of physical memory pages and maps them into | |
| // an available virtual region. This function returns |SB_MEMORY_MAP_FAILED| | |
| // on failure. |NULL| is a valid return value. | |
| // | |
| // |size_bytes|: The amount of physical memory pages to be allocated. | |
| // |flags|: The bitwise OR of the protection flags for the mapped memory | |
| // as specified in |SbMemoryMapFlags|. Allocating executable memory is not | |
| // allowed and will fail. If executable memory is needed, map non-executable | |
| // memory first and then switch access to executable using SbMemoryProtect. | |
| // When kSbMemoryMapProtectReserved is used, the address space will not be | |
| // accessible and, if possible, the platform should not count it against any | |
| // memory budget. | |
| // |name|: A value that appears in the debugger on some platforms. The value | |
| // can be up to 32 bytes. | |
| SB_EXPORT void* SbMemoryMap(int64_t size_bytes, int flags, const char* name); | |
| // Unmap |size_bytes| of physical pages starting from |virtual_address|, | |
| // returning |true| on success. After this function completes, | |
| // [virtual_address, virtual_address + size_bytes) will not be read/writable. | |
| // This function can unmap multiple contiguous regions that were mapped with | |
| // separate calls to SbMemoryMap(). For example, if one call to | |
| // |SbMemoryMap(0x1000)| returns |(void*)0xA000|, and another call to | |
| // |SbMemoryMap(0x1000)| returns |(void*)0xB000|, | |
| // |SbMemoryUnmap(0xA000, 0x2000)| should free both regions. | |
| SB_EXPORT bool SbMemoryUnmap(void* virtual_address, int64_t size_bytes); | |
| #if SB_API_VERSION >= 10 | |
| // Change the protection of |size_bytes| of memory regions, starting from | |
| // |virtual_address|, to |flags|, returning |true| on success. | |
| SB_EXPORT bool SbMemoryProtect(void* virtual_address, | |
| int64_t size_bytes, | |
| int flags); | |
| #endif | |
| #if SB_CAN(MAP_EXECUTABLE_MEMORY) | |
| // Flushes any data in the given virtual address range that is cached locally in | |
| // the current processor core to physical memory, ensuring that data and | |
| // instruction caches are cleared. This is required to be called on executable | |
| // memory that has been written to and might be executed in the future. | |
| SB_EXPORT void SbMemoryFlush(void* virtual_address, int64_t size_bytes); | |
| #endif | |
| #endif // SB_API_VERSION >= SB_MMAP_REQUIRED_VERSION || SB_HAS(MMAP) | |
| // Gets the stack bounds for the current thread. | |
| // | |
| // |out_high|: The highest addressable byte + 1 for the current thread. | |
| // |out_low|: The lowest addressable byte for the current thread. | |
| SB_EXPORT void SbMemoryGetStackBounds(void** out_high, void** out_low); | |
| // Copies |count| sequential bytes from |source| to |destination|, without | |
| // support for the |source| and |destination| regions overlapping. This | |
| // function is meant to be a drop-in replacement for |memcpy|. | |
| // | |
| // The function's behavior is undefined if |destination| or |source| are NULL, | |
| // and the function is a no-op if |count| is 0. The return value is | |
| // |destination|. | |
| // | |
| // |destination|: The destination of the copied memory. | |
| // |source|: The source of the copied memory. | |
| // |count|: The number of sequential bytes to be copied. | |
| SB_EXPORT void* SbMemoryCopy(void* destination, | |
| const void* source, | |
| size_t count); | |
| // Copies |count| sequential bytes from |source| to |destination|, with support | |
| // for the |source| and |destination| regions overlapping. This function is | |
| // meant to be a drop-in replacement for |memmove|. | |
| // | |
| // The function's behavior is undefined if |destination| or |source| are NULL, | |
| // and the function is a no-op if |count| is 0. The return value is | |
| // |destination|. | |
| // | |
| // |destination|: The destination of the copied memory. | |
| // |source|: The source of the copied memory. | |
| // |count|: The number of sequential bytes to be copied. | |
| SB_EXPORT void* SbMemoryMove(void* destination, | |
| const void* source, | |
| size_t count); | |
| // Fills |count| sequential bytes starting at |destination|, with the unsigned | |
| // char coercion of |byte_value|. This function is meant to be a drop-in | |
| // replacement for |memset|. | |
| // | |
| // The function's behavior is undefined if |destination| is NULL, and the | |
| // function is a no-op if |count| is 0. The return value is |destination|. | |
| // | |
| // |destination|: The destination of the copied memory. | |
| // |count|: The number of sequential bytes to be set. | |
| SB_EXPORT void* SbMemorySet(void* destination, int byte_value, size_t count); | |
| // Compares the contents of the first |count| bytes of |buffer1| and |buffer2|. | |
| // This function returns: | |
| // - |-1| if |buffer1| is "less-than" |buffer2| | |
| // - |0| if |buffer1| and |buffer2| are equal | |
| // - |1| if |buffer1| is "greater-than" |buffer2|. | |
| // | |
| // This function is meant to be a drop-in replacement for |memcmp|. | |
| // | |
| // |buffer1|: The first buffer to be compared. | |
| // |buffer2|: The second buffer to be compared. | |
| // |count|: The number of bytes to be compared. | |
| SB_EXPORT int SbMemoryCompare(const void* buffer1, | |
| const void* buffer2, | |
| size_t count); | |
| // Finds the lower 8-bits of |value| in the first |count| bytes of |buffer| | |
| // and returns either a pointer to the first found occurrence or |NULL| if | |
| // the value is not found. This function is meant to be a drop-in replacement | |
| // for |memchr|. | |
| SB_EXPORT const void* SbMemoryFindByte(const void* buffer, | |
| int value, | |
| size_t count); | |
| // A wrapper that implements a drop-in replacement for |calloc|, which is used | |
| // in some packages. | |
| static SB_C_INLINE void* SbMemoryCalloc(size_t count, size_t size) { | |
| size_t total = count * size; | |
| void* result = SbMemoryAllocate(total); | |
| if (result) { | |
| SbMemorySet(result, 0, total); | |
| } | |
| return result; | |
| } | |
| // Returns true if the first |count| bytes of |buffer| are set to zero. | |
| static SB_C_INLINE bool SbMemoryIsZero(const void* buffer, size_t count) { | |
| if (count == 0) { | |
| return true; | |
| } | |
| const char* char_buffer = (const char*)(buffer); | |
| return char_buffer[0] == 0 && | |
| SbMemoryCompare(char_buffer, char_buffer + 1, count - 1) == 0; | |
| } | |
| ///////////////////////////////////////////////////////////////// | |
| // Deprecated. Do not use. | |
| ///////////////////////////////////////////////////////////////// | |
| // Same as SbMemoryAllocateUnchecked, but will abort() in the case of an | |
| // allocation failure. | |
| // | |
| // DO NOT CALL. Call SbMemoryAllocate(...) instead. | |
| SB_DEPRECATED_EXTERNAL( | |
| SB_EXPORT void* SbMemoryAllocateChecked(size_t size)); | |
| // Same as SbMemoryReallocateUnchecked, but will abort() in the case of an | |
| // allocation failure. | |
| // | |
| // DO NOT CALL. Call SbMemoryReallocate(...) instead. | |
| SB_DEPRECATED_EXTERNAL( | |
| SB_EXPORT void* SbMemoryReallocateChecked(void* memory, size_t size)); | |
| // Same as SbMemoryAllocateAlignedUnchecked, but will abort() in the case of an | |
| // allocation failure. | |
| // | |
| // DO NOT CALL. Call SbMemoryAllocateAligned(...) instead. | |
| SB_DEPRECATED_EXTERNAL( | |
| SB_EXPORT void* SbMemoryAllocateAlignedChecked(size_t alignment, | |
| size_t size)); | |
| #ifdef __cplusplus | |
| } // extern "C" | |
| #endif | |
| #endif // STARBOARD_MEMORY_H_ |