blob: def0c34d5328fce33839f8f6bb9941ca6f8fce52 [file] [log] [blame]
// Copyright 2017 Google Inc. 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.
#ifndef gc_JSCUSTOMALLOCATOR_H
#define gc_JSCUSTOMALLOCATOR_H
#include <algorithm>
#include "memory_allocator_reporter.h"
#include "starboard/common/string.h"
#include "starboard/memory.h"
namespace js {
namespace oom {
// Code imported from default allocator. These identifiers must be supplied
// to SpiderMonkey common code.
/*
* To make testing OOM in certain helper threads more effective,
* allow restricting the OOM testing to a certain helper thread
* type. This allows us to fail e.g. in off-thread script parsing
* without causing an OOM in the main thread first.
*/
enum ThreadType {
THREAD_TYPE_NONE = 0, // 0
THREAD_TYPE_MAIN, // 1
THREAD_TYPE_ASMJS, // 2
THREAD_TYPE_ION, // 3
THREAD_TYPE_PARSE, // 4
THREAD_TYPE_COMPRESS, // 5
THREAD_TYPE_GCHELPER, // 6
THREAD_TYPE_GCPARALLEL, // 7
THREAD_TYPE_MAX // Used to check shell function arguments
};
/*
* Getter/Setter functions to encapsulate mozilla::ThreadLocal,
* implementation is in jsutil.cpp.
*/
# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
extern bool InitThreadType(void);
extern void SetThreadType(ThreadType);
extern uint32_t GetThreadType(void);
# else
inline bool InitThreadType(void) { return true; }
inline void SetThreadType(ThreadType t) {};
inline uint32_t GetThreadType(void) { return 0; }
# endif
} // namespace oom
} // namespace js
# if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
/*
* In order to test OOM conditions, when the testing function
* oomAfterAllocations COUNT is passed, we fail continuously after the NUM'th
* allocation from now.
*/
extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set in builtin/TestingFunctions.cpp */
extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */
extern JS_PUBLIC_DATA(bool) OOM_failAlways;
#define JS_OOM_CALL_BP_FUNC() do {} while(0)
namespace js {
namespace oom {
extern JS_PUBLIC_DATA(uint32_t) targetThread;
static inline bool
IsThreadSimulatingOOM()
{
return false;
}
static inline bool
IsSimulatedOOMAllocation()
{
return false;
}
static inline bool
ShouldFailWithOOM()
{
return false;
}
} // namespace oom
} // namespace js
# define JS_OOM_POSSIBLY_FAIL() \
do { \
if (js::oom::ShouldFailWithOOM()) \
return nullptr; \
} while (0)
# define JS_OOM_POSSIBLY_FAIL_BOOL() \
do { \
if (js::oom::ShouldFailWithOOM()) \
return false; \
} while (0)
# else // defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
# define JS_OOM_POSSIBLY_FAIL() do {} while(0)
# define JS_OOM_POSSIBLY_FAIL_BOOL() do {} while(0)
namespace js {
namespace oom {
static inline bool IsSimulatedOOMAllocation() { return false; }
static inline bool ShouldFailWithOOM() { return false; }
} // namespace oom
} // namespace js
# endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
namespace js {
struct MOZ_RAII AutoEnterOOMUnsafeRegion
{
MOZ_NORETURN MOZ_COLD void crash(const char* reason);
};
} // namespace js
static inline void* js_malloc(size_t bytes)
{
size_t reservation_bytes = AllocationMetadata::GetReservationBytes(bytes);
MemoryAllocatorReporter::Get()->UpdateTotalHeapSize(reservation_bytes);
void* metadata = SbMemoryAllocate(reservation_bytes);
AllocationMetadata::SetSizeToBaseAddress(metadata, reservation_bytes);
return AllocationMetadata::GetUserAddressFromBaseAddress(metadata);
}
static inline void* js_calloc(size_t nmemb, size_t size)
{
size_t total_size = nmemb * size;
void* memory = js_malloc(total_size);
if (memory) {
SbMemorySet(memory, 0, total_size);
}
return memory;
}
static inline void* js_calloc(size_t bytes)
{
return js_calloc(bytes, 1);
}
static inline void* js_realloc(void* p, size_t bytes)
{
AllocationMetadata* metadata =
AllocationMetadata::GetMetadataFromUserAddress(p);
size_t current_size =
AllocationMetadata::GetSizeOfAllocationFromMetadata(metadata);
size_t adjusted_size = AllocationMetadata::GetReservationBytes(bytes);
MemoryAllocatorReporter::Get()->UpdateTotalHeapSize(
static_cast<ssize_t>(adjusted_size - current_size));
void* new_ptr = SbMemoryReallocate(metadata, adjusted_size);
AllocationMetadata::SetSizeToBaseAddress(new_ptr, adjusted_size);
return AllocationMetadata::GetUserAddressFromBaseAddress(new_ptr);
}
static inline void js_free(void* p)
{
if (p == NULL) {
return;
}
AllocationMetadata* metadata =
AllocationMetadata::GetMetadataFromUserAddress(p);
MemoryAllocatorReporter::Get()->UpdateTotalHeapSize(-static_cast<ssize_t>(
AllocationMetadata::GetSizeOfAllocationFromMetadata(metadata)));
SbMemoryDeallocate(metadata);
}
static inline char* js_strdup(const char* s)
{
size_t length = SbStringGetLength(s) + 1;
char* new_ptr = reinterpret_cast<char*>(js_malloc(length));
SbStringCopy(new_ptr, s, length);
return new_ptr;
}
#endif // gc_JSCUSTOMALLOCATOR_H