diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index 4b102040a5..c5eea14d8a 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -1070,15 +1070,22 @@ TNode CodeStubAssembler::AllocateRaw(TNode size_in_bytes, AllocationFlags flags, TNode top_address, TNode 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 top = @@ -1165,6 +1172,13 @@ TNode CodeStubAssembler::AllocateRaw(TNode 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(result.value()); } @@ -4106,6 +4120,28 @@ TNode 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(kMaxLength), mode), mode), + &if_out_of_memory, &next); + + BIND(&if_out_of_memory); + CallRuntime(Runtime::kFatalProcessOutOfMemoryInvalidArrayLength, + NoContextConstant()); + Unreachable(); + + BIND(&next); + } + TNode total_size = GetFixedArrayAllocationSize(capacity, kind, mode); if (IsDoubleElementsKind(kind)) flags |= kDoubleAlignment; diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index 9e24f87452..bd21c7d6fd 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -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(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 BIntToSmi(TNode source) { return source; } TNode BIntToIntPtr(TNode source) { diff --git a/src/runtime/runtime-internal.cc b/src/runtime/runtime-internal.cc index 8666cfd273..92f2265eeb 100644 --- a/src/runtime/runtime-internal.cc +++ b/src/runtime/runtime-internal.cc @@ -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()); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index fb611c212f..50ccdc61c9 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -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) \