Commit b33179ae authored by Clemens Backes's avatar Clemens Backes Committed by V8 LUCI CQ

[API] Pass OOMDetails to OOMErrorCallback

This adds a new struct "OOMDetails" which is passed to the
OOMErrorCallback. It currently holds the "is_heap_oom" bool that was
also passed before, plus an optional "detail" string.
The struct can later be extended without having to change the signature
of the OOMErrorCallback. Removing fields will have to follow the
standard deprecation rules, but this is also easily possible without the
hassle for this initial change.

We modify the deprecated OOMErrorCallback definition and un-deprecate it,
which can be seen as removing a deprecated API and adding a new one in
one CL.

R=mlippautz@chromium.org, jkummerow@chromium.org

Bug: chromium:1323177
Change-Id: Ic4c2cb5856906ebd664626fe463d8e96cb99b0a5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3647827Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80565}
parent ab7435a2
...@@ -216,14 +216,17 @@ using AddHistogramSampleCallback = void (*)(void* histogram, int sample); ...@@ -216,14 +216,17 @@ using AddHistogramSampleCallback = void (*)(void* histogram, int sample);
using FatalErrorCallback = void (*)(const char* location, const char* message); using FatalErrorCallback = void (*)(const char* location, const char* message);
using LegacyOOMErrorCallback = void (*)(const char* location, bool is_heap_oom); using LegacyOOMErrorCallback V8_DEPRECATE_SOON(
"Use OOMErrorCallback (https://crbug.com/1323177)") =
// TODO(chromium:1323177): Add a parameter for details, once this is deprecated void (*)(const char* location, bool is_heap_oom);
// for at least one branch.
using OOMErrorCallback V8_DEPRECATED( struct OOMDetails {
"Use LegacyOOMErrorCallback; OOMErrorCallback will be changed " bool is_heap_oom = false;
"(https://crbug.com/1323177)") = void (*)(const char* location, const char* detail = nullptr;
bool is_heap_oom); };
using OOMErrorCallback = void (*)(const char* location,
const OOMDetails& details);
using MessageCallback = void (*)(Local<Message> message, Local<Value> data); using MessageCallback = void (*)(Local<Message> message, Local<Value> data);
......
...@@ -284,6 +284,9 @@ class V8_EXPORT V8 { ...@@ -284,6 +284,9 @@ class V8_EXPORT V8 {
* v8 has encountered a fatal failure to allocate memory and is about to * v8 has encountered a fatal failure to allocate memory and is about to
* terminate. * terminate.
*/ */
static void SetFatalMemoryErrorCallback(OOMErrorCallback callback);
V8_DEPRECATE_SOON("Use OOMErrorCallback (https://crbug.com/1323177)")
static void SetFatalMemoryErrorCallback(LegacyOOMErrorCallback callback); static void SetFatalMemoryErrorCallback(LegacyOOMErrorCallback callback);
/** /**
......
...@@ -286,12 +286,11 @@ class V8_EXPORT Isolate { ...@@ -286,12 +286,11 @@ class V8_EXPORT Isolate {
* Callbacks to invoke in case of fatal or OOM errors. * Callbacks to invoke in case of fatal or OOM errors.
*/ */
FatalErrorCallback fatal_error_callback = nullptr; FatalErrorCallback fatal_error_callback = nullptr;
LegacyOOMErrorCallback legacy_oom_error_callback = nullptr;
V8_DEPRECATED(
"Use legacy_oom_error_callback; OOMErrorCallback will be changed soon "
"(https://crbug.com/1323177)")
OOMErrorCallback oom_error_callback = nullptr; OOMErrorCallback oom_error_callback = nullptr;
V8_DEPRECATE_SOON("Use oom_error_callback (https://crbug.com/1323177)")
LegacyOOMErrorCallback legacy_oom_error_callback = nullptr;
/** /**
* The following parameter is experimental and may change significantly. * The following parameter is experimental and may change significantly.
* This is currently for internal testing. * This is currently for internal testing.
...@@ -1478,9 +1477,13 @@ class V8_EXPORT Isolate { ...@@ -1478,9 +1477,13 @@ class V8_EXPORT Isolate {
/** Set the callback to invoke in case of fatal errors. */ /** Set the callback to invoke in case of fatal errors. */
void SetFatalErrorHandler(FatalErrorCallback that); void SetFatalErrorHandler(FatalErrorCallback that);
/** Set the callback to invoke in case of OOM errors. */ /** Set the callback to invoke in case of OOM errors (deprecated). */
V8_DEPRECATE_SOON("Use OOMErrorCallback (https://crbug.com/1323177)")
void SetOOMErrorHandler(LegacyOOMErrorCallback that); void SetOOMErrorHandler(LegacyOOMErrorCallback that);
/** Set the callback to invoke in case of OOM errors. */
void SetOOMErrorHandler(OOMErrorCallback that);
/** /**
* Add a callback to invoke in case the heap size is close to the heap limit. * Add a callback to invoke in case the heap size is close to the heap limit.
* If multiple callbacks are added, only the most recently added callback is * If multiple callbacks are added, only the most recently added callback is
......
...@@ -167,9 +167,14 @@ ...@@ -167,9 +167,14 @@
namespace v8 { namespace v8 {
// TODO(chromium:1323177): Add a separate global for OOMErrorCallback once the // Redefine LegacyOOMErrorCallback here for internal usage. We still need to
// types diverge. // support it but it is deprecated so would trigger warnings.
static LegacyOOMErrorCallback g_oom_error_callback = nullptr; // TODO(chromium:1323177): Remove this.
using DeprecatedLegacyOOMErrorCallback = void (*)(const char* location,
bool is_heap_oom);
static DeprecatedLegacyOOMErrorCallback g_legacy_oom_error_callback = nullptr;
static OOMErrorCallback g_oom_error_callback = nullptr;
static ScriptOrigin GetScriptOriginForScript(i::Isolate* i_isolate, static ScriptOrigin GetScriptOriginForScript(i::Isolate* i_isolate,
i::Handle<i::Script> script) { i::Handle<i::Script> script) {
...@@ -207,7 +212,7 @@ Local<PrimitiveArray> ScriptOrigin::HostDefinedOptions() const { ...@@ -207,7 +212,7 @@ Local<PrimitiveArray> ScriptOrigin::HostDefinedOptions() const {
// When V8 cannot allocate memory FatalProcessOutOfMemory is called. The default // When V8 cannot allocate memory FatalProcessOutOfMemory is called. The default
// OOM error handler is called and execution is stopped. // OOM error handler is called and execution is stopped.
void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location, void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location,
bool is_heap_oom) { const OOMDetails& details) {
char last_few_messages[Heap::kTraceRingBufferSize + 1]; char last_few_messages[Heap::kTraceRingBufferSize + 1];
char js_stacktrace[Heap::kStacktraceBufferSize + 1]; char js_stacktrace[Heap::kStacktraceBufferSize + 1];
i::HeapStats heap_stats; i::HeapStats heap_stats;
...@@ -225,7 +230,10 @@ void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location, ...@@ -225,7 +230,10 @@ void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location,
memset(&heap_stats, 0xBADC0DE, sizeof(heap_stats)); memset(&heap_stats, 0xBADC0DE, sizeof(heap_stats));
// Give the embedder a chance to handle the condition. If it doesn't, // Give the embedder a chance to handle the condition. If it doesn't,
// just crash. // just crash.
if (g_oom_error_callback) g_oom_error_callback(location, is_heap_oom); if (g_oom_error_callback) g_oom_error_callback(location, details);
if (g_legacy_oom_error_callback) {
g_legacy_oom_error_callback(location, details.is_heap_oom);
}
FATAL("Fatal process out of memory: %s", location); FATAL("Fatal process out of memory: %s", location);
UNREACHABLE(); UNREACHABLE();
} }
...@@ -299,8 +307,11 @@ void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location, ...@@ -299,8 +307,11 @@ void i::V8::FatalProcessOutOfMemory(i::Isolate* i_isolate, const char* location,
base::OS::PrintError("\n<--- JS stacktrace --->\n%s\n", js_stacktrace); base::OS::PrintError("\n<--- JS stacktrace --->\n%s\n", js_stacktrace);
} }
} }
Utils::ReportOOMFailure(i_isolate, location, is_heap_oom); Utils::ReportOOMFailure(i_isolate, location, details);
if (g_oom_error_callback) g_oom_error_callback(location, is_heap_oom); if (g_oom_error_callback) g_oom_error_callback(location, details);
if (g_legacy_oom_error_callback) {
g_legacy_oom_error_callback(location, details.is_heap_oom);
}
// If the fatal error handler returns, we stop execution. // If the fatal error handler returns, we stop execution.
FATAL("API fatal error handler returned after process out of memory"); FATAL("API fatal error handler returned after process out of memory");
} }
...@@ -322,15 +333,19 @@ void Utils::ReportApiFailure(const char* location, const char* message) { ...@@ -322,15 +333,19 @@ void Utils::ReportApiFailure(const char* location, const char* message) {
} }
void Utils::ReportOOMFailure(i::Isolate* i_isolate, const char* location, void Utils::ReportOOMFailure(i::Isolate* i_isolate, const char* location,
bool is_heap_oom) { const OOMDetails& details) {
LegacyOOMErrorCallback oom_callback = i_isolate->oom_behavior(); if (auto oom_callback = i_isolate->oom_behavior()) {
if (oom_callback == nullptr) { oom_callback(location, details);
} else if (auto legacy_oom_callback = i_isolate->legacy_oom_behavior()) {
legacy_oom_callback(location, details.is_heap_oom);
} else {
// TODO(wfh): Remove this fallback once Blink is setting OOM handler. See // TODO(wfh): Remove this fallback once Blink is setting OOM handler. See
// crbug.com/614440. // crbug.com/614440.
FatalErrorCallback fatal_callback = i_isolate->exception_behavior(); FatalErrorCallback fatal_callback = i_isolate->exception_behavior();
if (fatal_callback == nullptr) { if (fatal_callback == nullptr) {
base::OS::PrintError("\n#\n# Fatal %s OOM in %s\n#\n\n", base::OS::PrintError("\n#\n# Fatal %s OOM in %s\n#\n\n",
is_heap_oom ? "javascript" : "process", location); details.is_heap_oom ? "javascript" : "process",
location);
#ifdef V8_FUZZILLI #ifdef V8_FUZZILLI
exit(0); exit(0);
#else #else
...@@ -338,12 +353,10 @@ void Utils::ReportOOMFailure(i::Isolate* i_isolate, const char* location, ...@@ -338,12 +353,10 @@ void Utils::ReportOOMFailure(i::Isolate* i_isolate, const char* location,
#endif // V8_FUZZILLI #endif // V8_FUZZILLI
} else { } else {
fatal_callback(location, fatal_callback(location,
is_heap_oom details.is_heap_oom
? "Allocation failed - JavaScript heap out of memory" ? "Allocation failed - JavaScript heap out of memory"
: "Allocation failed - process out of memory"); : "Allocation failed - process out of memory");
} }
} else {
oom_callback(location, is_heap_oom);
} }
i_isolate->SignalFatalError(); i_isolate->SignalFatalError();
} }
...@@ -6129,10 +6142,15 @@ void V8::SetUnhandledExceptionCallback( ...@@ -6129,10 +6142,15 @@ void V8::SetUnhandledExceptionCallback(
#endif // V8_OS_WIN #endif // V8_OS_WIN
void v8::V8::SetFatalMemoryErrorCallback( void v8::V8::SetFatalMemoryErrorCallback(
v8::LegacyOOMErrorCallback oom_error_callback) { v8::OOMErrorCallback oom_error_callback) {
g_oom_error_callback = oom_error_callback; g_oom_error_callback = oom_error_callback;
} }
void v8::V8::SetFatalMemoryErrorCallback(
v8::LegacyOOMErrorCallback legacy_oom_error_callback) {
g_legacy_oom_error_callback = legacy_oom_error_callback;
}
void v8::V8::SetEntropySource(EntropySource entropy_source) { void v8::V8::SetEntropySource(EntropySource entropy_source) {
base::RandomNumberGenerator::SetEntropySource(entropy_source); base::RandomNumberGenerator::SetEntropySource(entropy_source);
} }
...@@ -9393,7 +9411,9 @@ size_t Isolate::CopyCodePages(size_t capacity, MemoryRange* code_pages_out) { ...@@ -9393,7 +9411,9 @@ size_t Isolate::CopyCodePages(size_t capacity, MemoryRange* code_pages_out) {
} }
CALLBACK_SETTER(FatalErrorHandler, FatalErrorCallback, exception_behavior) CALLBACK_SETTER(FatalErrorHandler, FatalErrorCallback, exception_behavior)
CALLBACK_SETTER(OOMErrorHandler, LegacyOOMErrorCallback, oom_behavior) CALLBACK_SETTER(OOMErrorHandler, OOMErrorCallback, oom_behavior)
CALLBACK_SETTER(OOMErrorHandler, DeprecatedLegacyOOMErrorCallback,
legacy_oom_behavior)
CALLBACK_SETTER(ModifyCodeGenerationFromStringsCallback, CALLBACK_SETTER(ModifyCodeGenerationFromStringsCallback,
ModifyCodeGenerationFromStringsCallback2, ModifyCodeGenerationFromStringsCallback2,
modify_code_gen_callback2) modify_code_gen_callback2)
......
...@@ -156,7 +156,7 @@ class Utils { ...@@ -156,7 +156,7 @@ class Utils {
return condition; return condition;
} }
static void ReportOOMFailure(v8::internal::Isolate* isolate, static void ReportOOMFailure(v8::internal::Isolate* isolate,
const char* location, bool is_heap_oom); const char* location, const OOMDetails& details);
static inline Local<debug::AccessorPair> ToLocal( static inline Local<debug::AccessorPair> ToLocal(
v8::internal::Handle<v8::internal::AccessorPair> obj); v8::internal::Handle<v8::internal::AccessorPair> obj);
......
...@@ -476,10 +476,17 @@ V8_EXPORT_PRIVATE void FreeCurrentEmbeddedBlob(); ...@@ -476,10 +476,17 @@ V8_EXPORT_PRIVATE void FreeCurrentEmbeddedBlob();
using DebugObjectCache = std::vector<Handle<HeapObject>>; using DebugObjectCache = std::vector<Handle<HeapObject>>;
// Redefine LegacyOOMErrorCallback here for internal usage. We still need to
// support it but it is deprecated so would trigger warnings.
// TODO(chromium:1323177): Remove this.
using DeprecatedLegacyOOMErrorCallback = void (*)(const char* location,
bool is_heap_oom);
#define ISOLATE_INIT_LIST(V) \ #define ISOLATE_INIT_LIST(V) \
/* Assembler state. */ \ /* Assembler state. */ \
V(FatalErrorCallback, exception_behavior, nullptr) \ V(FatalErrorCallback, exception_behavior, nullptr) \
V(LegacyOOMErrorCallback, oom_behavior, nullptr) \ V(DeprecatedLegacyOOMErrorCallback, legacy_oom_behavior, nullptr) \
V(OOMErrorCallback, oom_behavior, nullptr) \
V(LogEventCallback, event_logger, nullptr) \ V(LogEventCallback, event_logger, nullptr) \
V(AllowCodeGenerationFromStringsCallback, allow_code_gen_callback, nullptr) \ V(AllowCodeGenerationFromStringsCallback, allow_code_gen_callback, nullptr) \
V(ModifyCodeGenerationFromStringsCallback, modify_code_gen_callback, \ V(ModifyCodeGenerationFromStringsCallback, modify_code_gen_callback, \
......
...@@ -127,8 +127,8 @@ AllocationResult HeapAllocator::AllocateRawWithRetryOrFailSlowPath( ...@@ -127,8 +127,8 @@ AllocationResult HeapAllocator::AllocateRawWithRetryOrFailSlowPath(
return result; return result;
} }
v8::internal::V8::FatalProcessOutOfMemory(heap_->isolate(), V8::FatalProcessOutOfMemory(heap_->isolate(), "CALL_AND_RETRY_LAST",
"CALL_AND_RETRY_LAST", true); V8::kHeapOOM);
} }
#ifdef DEBUG #ifdef DEBUG
......
...@@ -6363,7 +6363,7 @@ void Heap::CompactRetainedMaps(WeakArrayList retained_maps) { ...@@ -6363,7 +6363,7 @@ void Heap::CompactRetainedMaps(WeakArrayList retained_maps) {
} }
void Heap::FatalProcessOutOfMemory(const char* location) { void Heap::FatalProcessOutOfMemory(const char* location) {
v8::internal::V8::FatalProcessOutOfMemory(isolate(), location, true); V8::FatalProcessOutOfMemory(isolate(), location, V8::kHeapOOM);
} }
#ifdef DEBUG #ifdef DEBUG
......
...@@ -49,7 +49,8 @@ void PromoteYoungGenerationGC::EvacuateYoungGeneration() { ...@@ -49,7 +49,8 @@ void PromoteYoungGenerationGC::EvacuateYoungGeneration() {
// Reset new space. // Reset new space.
semi_space_new_space->EvacuatePrologue(); semi_space_new_space->EvacuatePrologue();
if (!semi_space_new_space->Rebalance()) { if (!semi_space_new_space->Rebalance()) {
V8::FatalProcessOutOfMemory(heap_->isolate(), "NewSpace::Rebalance", true); V8::FatalProcessOutOfMemory(heap_->isolate(), "NewSpace::Rebalance",
V8::kHeapOOM);
} }
semi_space_new_space->set_age_mark(semi_space_new_space->top()); semi_space_new_space->set_age_mark(semi_space_new_space->top());
......
...@@ -38,7 +38,10 @@ ...@@ -38,7 +38,10 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
// static
v8::Platform* V8::platform_ = nullptr; v8::Platform* V8::platform_ = nullptr;
const OOMDetails V8::kNoOOMDetails{false, nullptr};
const OOMDetails V8::kHeapOOM{true, nullptr};
namespace { namespace {
enum class V8StartupState { enum class V8StartupState {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
namespace v8 { namespace v8 {
struct OOMDetails;
class Platform; class Platform;
class StartupData; class StartupData;
...@@ -27,7 +28,13 @@ class V8 : public AllStatic { ...@@ -27,7 +28,13 @@ class V8 : public AllStatic {
// IMPORTANT: Update the Google-internal crash processer if this signature // IMPORTANT: Update the Google-internal crash processer if this signature
// changes to be able to extract detailed v8::internal::HeapStats on OOM. // changes to be able to extract detailed v8::internal::HeapStats on OOM.
[[noreturn]] V8_EXPORT_PRIVATE static void FatalProcessOutOfMemory( [[noreturn]] V8_EXPORT_PRIVATE static void FatalProcessOutOfMemory(
Isolate* isolate, const char* location, bool is_heap_oom = false); Isolate* isolate, const char* location,
const OOMDetails& details = kNoOOMDetails);
// Constants to be used for V8::FatalProcessOutOfMemory. They avoid having
// to include v8-callbacks.h in all callers.
V8_EXPORT_PRIVATE static const OOMDetails kNoOOMDetails;
V8_EXPORT_PRIVATE static const OOMDetails kHeapOOM;
#ifdef V8_ENABLE_SANDBOX #ifdef V8_ENABLE_SANDBOX
static bool InitializeSandbox(); static bool InitializeSandbox();
......
...@@ -6819,7 +6819,7 @@ UNINITIALIZED_TEST(ReinitializeStringHashSeed) { ...@@ -6819,7 +6819,7 @@ UNINITIALIZED_TEST(ReinitializeStringHashSeed) {
const int kHeapLimit = 100 * MB; const int kHeapLimit = 100 * MB;
Isolate* oom_isolate = nullptr; Isolate* oom_isolate = nullptr;
void OOMCallback(const char* location, bool is_heap_oom) { void OOMCallback(const char* location, const OOMDetails&) {
Heap* heap = oom_isolate->heap(); Heap* heap = oom_isolate->heap();
size_t kSlack = heap->new_space() ? heap->MaxSemiSpaceSize() : 0; size_t kSlack = heap->new_space() ? heap->MaxSemiSpaceSize() : 0;
CHECK_LE(heap->OldGenerationCapacity(), kHeapLimit + kSlack); CHECK_LE(heap->OldGenerationCapacity(), kHeapLimit + kSlack);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment