blob: c9e769109322c506b36a40dbbd02fe7c7fbbd53e [file] [log] [blame]
// 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_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_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_