[csa] Call FatalProcessOutOfMemory in OOM situations
OOMs in CSA code would trigger fairly arbitrary assertion failures on some paths. This changes CSA::AllocateRaw to call FatalProcessOutOfMemory (just like runtime methods). CSA::AllocateFixedArray additionally checks for FixedArray::kMaxLength. This increases overall builtin code size on x64 release by 28K / 2.5%. Bug: chromium:917561, chromium:848672 Change-Id: I757271264f396e0df8d8fe0570bad078075c27d5 Reviewed-on: https://chromium-review.googlesource.com/c/1400414 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/master@{#58654}
This commit is contained in:
parent
934af8dde9
commit
ba712bf89f
@ -1070,15 +1070,22 @@ TNode<HeapObject> CodeStubAssembler::AllocateRaw(TNode<IntPtrT> size_in_bytes,
|
||||
AllocationFlags flags,
|
||||
TNode<RawPtrT> top_address,
|
||||
TNode<RawPtrT> limit_address) {
|
||||
// TODO(jgruber, chromium:848672): Call FatalProcessOutOfMemory if this fails.
|
||||
{
|
||||
intptr_t constant_value;
|
||||
if (ToIntPtrConstant(size_in_bytes, constant_value)) {
|
||||
CHECK(Internals::IsValidSmi(constant_value));
|
||||
CHECK_GT(constant_value, 0);
|
||||
} else {
|
||||
CSA_CHECK(this, IsValidPositiveSmi(size_in_bytes));
|
||||
}
|
||||
Label if_out_of_memory(this, Label::kDeferred);
|
||||
|
||||
// TODO(jgruber,jkummerow): Extract the slow paths (= probably everything
|
||||
// but bump pointer allocation) into a builtin to save code space. The
|
||||
// size_in_bytes check may be moved there as well since a non-smi
|
||||
// size_in_bytes probably doesn't fit into the bump pointer region
|
||||
// (double-check that).
|
||||
|
||||
intptr_t size_in_bytes_constant;
|
||||
bool size_in_bytes_is_constant = false;
|
||||
if (ToIntPtrConstant(size_in_bytes, size_in_bytes_constant)) {
|
||||
size_in_bytes_is_constant = true;
|
||||
CHECK(Internals::IsValidSmi(size_in_bytes_constant));
|
||||
CHECK_GT(size_in_bytes_constant, 0);
|
||||
} else {
|
||||
GotoIfNot(IsValidPositiveSmi(size_in_bytes), &if_out_of_memory);
|
||||
}
|
||||
|
||||
TNode<RawPtrT> top =
|
||||
@ -1165,6 +1172,13 @@ TNode<HeapObject> CodeStubAssembler::AllocateRaw(TNode<IntPtrT> size_in_bytes,
|
||||
Goto(&out);
|
||||
}
|
||||
|
||||
if (!size_in_bytes_is_constant) {
|
||||
BIND(&if_out_of_memory);
|
||||
CallRuntime(Runtime::kFatalProcessOutOfMemoryInAllocateRaw,
|
||||
NoContextConstant());
|
||||
Unreachable();
|
||||
}
|
||||
|
||||
BIND(&out);
|
||||
return UncheckedCast<HeapObject>(result.value());
|
||||
}
|
||||
@ -4106,6 +4120,28 @@ TNode<FixedArrayBase> CodeStubAssembler::AllocateFixedArray(
|
||||
CSA_SLOW_ASSERT(this, MatchesParameterMode(capacity, mode));
|
||||
CSA_ASSERT(this, IntPtrOrSmiGreaterThan(capacity,
|
||||
IntPtrOrSmiConstant(0, mode), mode));
|
||||
|
||||
const intptr_t kMaxLength = IsDoubleElementsKind(kind)
|
||||
? FixedDoubleArray::kMaxLength
|
||||
: FixedArray::kMaxLength;
|
||||
intptr_t capacity_constant;
|
||||
if (ToParameterConstant(capacity, &capacity_constant, mode)) {
|
||||
CHECK_LE(capacity_constant, kMaxLength);
|
||||
} else {
|
||||
Label if_out_of_memory(this, Label::kDeferred), next(this);
|
||||
Branch(IntPtrOrSmiGreaterThan(
|
||||
capacity,
|
||||
IntPtrOrSmiConstant(static_cast<int>(kMaxLength), mode), mode),
|
||||
&if_out_of_memory, &next);
|
||||
|
||||
BIND(&if_out_of_memory);
|
||||
CallRuntime(Runtime::kFatalProcessOutOfMemoryInvalidArrayLength,
|
||||
NoContextConstant());
|
||||
Unreachable();
|
||||
|
||||
BIND(&next);
|
||||
}
|
||||
|
||||
TNode<IntPtrT> total_size = GetFixedArrayAllocationSize(capacity, kind, mode);
|
||||
|
||||
if (IsDoubleElementsKind(kind)) flags |= kDoubleAlignment;
|
||||
|
@ -275,6 +275,25 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
|
||||
return value;
|
||||
}
|
||||
|
||||
bool ToParameterConstant(Node* node, intptr_t* out, ParameterMode mode) {
|
||||
if (mode == ParameterMode::SMI_PARAMETERS) {
|
||||
Smi constant;
|
||||
if (ToSmiConstant(node, &constant)) {
|
||||
*out = static_cast<intptr_t>(constant->value());
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
DCHECK_EQ(mode, ParameterMode::INTPTR_PARAMETERS);
|
||||
intptr_t constant;
|
||||
if (ToIntPtrConstant(node, constant)) {
|
||||
*out = constant;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(V8_HOST_ARCH_32_BIT)
|
||||
TNode<Smi> BIntToSmi(TNode<BInt> source) { return source; }
|
||||
TNode<IntPtrT> BIntToIntPtr(TNode<BInt> source) {
|
||||
|
@ -32,6 +32,20 @@ RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_FatalProcessOutOfMemoryInAllocateRaw) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(0, args.length());
|
||||
isolate->heap()->FatalProcessOutOfMemory("CodeStubAssembler::AllocateRaw");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_FatalProcessOutOfMemoryInvalidArrayLength) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(0, args.length());
|
||||
isolate->heap()->FatalProcessOutOfMemory("invalid array length");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_Throw) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(1, args.length());
|
||||
|
@ -206,48 +206,50 @@ namespace internal {
|
||||
#define FOR_EACH_INTRINSIC_INTL(F, I)
|
||||
#endif // V8_INTL_SUPPORT
|
||||
|
||||
#define FOR_EACH_INTRINSIC_INTERNAL(F, I) \
|
||||
F(AllocateInNewSpace, 1, 1) \
|
||||
F(AllocateInTargetSpace, 2, 1) \
|
||||
F(AllocateSeqOneByteString, 1, 1) \
|
||||
F(AllocateSeqTwoByteString, 1, 1) \
|
||||
F(AllowDynamicFunction, 1, 1) \
|
||||
F(CheckIsBootstrapping, 0, 1) \
|
||||
I(CreateAsyncFromSyncIterator, 1, 1) \
|
||||
F(CreateListFromArrayLike, 1, 1) \
|
||||
F(CreateTemplateObject, 1, 1) \
|
||||
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
|
||||
F(IncrementUseCounter, 1, 1) \
|
||||
F(Interrupt, 0, 1) \
|
||||
F(NewReferenceError, 2, 1) \
|
||||
F(NewSyntaxError, 2, 1) \
|
||||
F(NewTypeError, 2, 1) \
|
||||
F(OrdinaryHasInstance, 2, 1) \
|
||||
F(PromoteScheduledException, 0, 1) \
|
||||
F(ReportMessage, 1, 1) \
|
||||
F(ReThrow, 1, 1) \
|
||||
F(RunMicrotaskCallback, 2, 1) \
|
||||
F(PerformMicrotaskCheckpoint, 0, 1) \
|
||||
F(StackGuard, 0, 1) \
|
||||
F(Throw, 1, 1) \
|
||||
F(ThrowApplyNonFunction, 1, 1) \
|
||||
F(ThrowCalledNonCallable, 1, 1) \
|
||||
F(ThrowConstructedNonConstructable, 1, 1) \
|
||||
F(ThrowConstructorReturnedNonObject, 0, 1) \
|
||||
F(ThrowInvalidStringLength, 0, 1) \
|
||||
F(ThrowInvalidTypedArrayAlignment, 2, 1) \
|
||||
F(ThrowIteratorError, 1, 1) \
|
||||
F(ThrowIteratorResultNotAnObject, 1, 1) \
|
||||
F(ThrowNotConstructor, 1, 1) \
|
||||
F(ThrowRangeError, -1 /* >= 1 */, 1) \
|
||||
F(ThrowReferenceError, 1, 1) \
|
||||
F(ThrowStackOverflow, 0, 1) \
|
||||
F(ThrowSymbolAsyncIteratorInvalid, 0, 1) \
|
||||
F(ThrowSymbolIteratorInvalid, 0, 1) \
|
||||
F(ThrowThrowMethodMissing, 0, 1) \
|
||||
F(ThrowTypeError, -1 /* >= 1 */, 1) \
|
||||
F(Typeof, 1, 1) \
|
||||
F(UnwindAndFindExceptionHandler, 0, 1) \
|
||||
#define FOR_EACH_INTRINSIC_INTERNAL(F, I) \
|
||||
F(AllocateInNewSpace, 1, 1) \
|
||||
F(AllocateInTargetSpace, 2, 1) \
|
||||
F(AllocateSeqOneByteString, 1, 1) \
|
||||
F(AllocateSeqTwoByteString, 1, 1) \
|
||||
F(AllowDynamicFunction, 1, 1) \
|
||||
F(CheckIsBootstrapping, 0, 1) \
|
||||
I(CreateAsyncFromSyncIterator, 1, 1) \
|
||||
F(CreateListFromArrayLike, 1, 1) \
|
||||
F(CreateTemplateObject, 1, 1) \
|
||||
F(FatalProcessOutOfMemoryInAllocateRaw, 0, 1) \
|
||||
F(FatalProcessOutOfMemoryInvalidArrayLength, 0, 1) \
|
||||
F(GetAndResetRuntimeCallStats, -1 /* <= 2 */, 1) \
|
||||
F(IncrementUseCounter, 1, 1) \
|
||||
F(Interrupt, 0, 1) \
|
||||
F(NewReferenceError, 2, 1) \
|
||||
F(NewSyntaxError, 2, 1) \
|
||||
F(NewTypeError, 2, 1) \
|
||||
F(OrdinaryHasInstance, 2, 1) \
|
||||
F(PromoteScheduledException, 0, 1) \
|
||||
F(ReportMessage, 1, 1) \
|
||||
F(ReThrow, 1, 1) \
|
||||
F(RunMicrotaskCallback, 2, 1) \
|
||||
F(PerformMicrotaskCheckpoint, 0, 1) \
|
||||
F(StackGuard, 0, 1) \
|
||||
F(Throw, 1, 1) \
|
||||
F(ThrowApplyNonFunction, 1, 1) \
|
||||
F(ThrowCalledNonCallable, 1, 1) \
|
||||
F(ThrowConstructedNonConstructable, 1, 1) \
|
||||
F(ThrowConstructorReturnedNonObject, 0, 1) \
|
||||
F(ThrowInvalidStringLength, 0, 1) \
|
||||
F(ThrowInvalidTypedArrayAlignment, 2, 1) \
|
||||
F(ThrowIteratorError, 1, 1) \
|
||||
F(ThrowIteratorResultNotAnObject, 1, 1) \
|
||||
F(ThrowNotConstructor, 1, 1) \
|
||||
F(ThrowRangeError, -1 /* >= 1 */, 1) \
|
||||
F(ThrowReferenceError, 1, 1) \
|
||||
F(ThrowStackOverflow, 0, 1) \
|
||||
F(ThrowSymbolAsyncIteratorInvalid, 0, 1) \
|
||||
F(ThrowSymbolIteratorInvalid, 0, 1) \
|
||||
F(ThrowThrowMethodMissing, 0, 1) \
|
||||
F(ThrowTypeError, -1 /* >= 1 */, 1) \
|
||||
F(Typeof, 1, 1) \
|
||||
F(UnwindAndFindExceptionHandler, 0, 1) \
|
||||
F(WeakFactoryCleanupJob, 1, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_LITERALS(F, I) \
|
||||
|
Loading…
Reference in New Issue
Block a user