From 9c9c8d7bb5681c9fe2a0c2bbe21f97f8b33d9c46 Mon Sep 17 00:00:00 2001 From: jgruber <jgruber@chromium.org> Date: Tue, 6 Dec 2016 06:08:41 -0800 Subject: [PATCH] [stubs] Add option to allow LO space allocation Passing kAllowLargeObjectAllocation now allocates in LOS if necessary. Allow such allocations when growing fixed arrays in RegExp's @@match and @@split operations. BUG=chromium:670671 Review-Url: https://codereview.chromium.org/2555703003 Cr-Commit-Position: refs/heads/master@{#41526} --- src/builtins/builtins-regexp.cc | 5 ++++- src/code-stub-assembler.cc | 16 ++++++++++++++++ src/code-stub-assembler.h | 3 ++- src/runtime/runtime-internal.cc | 2 +- test/mjsunit/regress/regress-670671.js | 23 +++++++++++++++++++++++ 5 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 test/mjsunit/regress/regress-670671.js diff --git a/src/builtins/builtins-regexp.cc b/src/builtins/builtins-regexp.cc index a08823553f..86871d24c1 100644 --- a/src/builtins/builtins-regexp.cc +++ b/src/builtins/builtins-regexp.cc @@ -1465,9 +1465,12 @@ class GrowableFixedArray { const ElementsKind kind = FAST_ELEMENTS; const WriteBarrierMode barrier_mode = UPDATE_WRITE_BARRIER; + const CodeStubAssembler::AllocationFlags flags = + CodeStubAssembler::kAllowLargeObjectAllocation; Node* const from_array = var_array_.value(); - Node* const to_array = a->AllocateFixedArray(kind, new_capacity, mode); + Node* const to_array = + a->AllocateFixedArray(kind, new_capacity, mode, flags); a->CopyFixedArrayElements(kind, from_array, kind, to_array, current_capacity, new_capacity, barrier_mode, mode); diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc index 776408ae08..27db1b8516 100644 --- a/src/code-stub-assembler.cc +++ b/src/code-stub-assembler.cc @@ -783,6 +783,22 @@ Node* CodeStubAssembler::AllocateRawUnaligned(Node* size_in_bytes, Label runtime_call(this, Label::kDeferred), no_runtime_call(this); Label merge_runtime(this, &result); + if (flags & kAllowLargeObjectAllocation) { + Label next(this); + GotoIf(IsRegularHeapObjectSize(size_in_bytes), &next); + + Node* runtime_flags = SmiConstant( + Smi::FromInt(AllocateDoubleAlignFlag::encode(false) | + AllocateTargetSpace::encode(AllocationSpace::LO_SPACE))); + Node* const runtime_result = + CallRuntime(Runtime::kAllocateInTargetSpace, NoContextConstant(), + SmiTag(size_in_bytes), runtime_flags); + result.Bind(runtime_result); + Goto(&merge_runtime); + + Bind(&next); + } + Node* new_top = IntPtrAdd(top, size_in_bytes); Branch(UintPtrGreaterThanOrEqual(new_top, limit), &runtime_call, &no_runtime_call); diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h index 27669d097e..7451f1ffcc 100644 --- a/src/code-stub-assembler.h +++ b/src/code-stub-assembler.h @@ -58,7 +58,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler { enum AllocationFlag : uint8_t { kNone = 0, kDoubleAlignment = 1, - kPretenured = 1 << 1 + kPretenured = 1 << 1, + kAllowLargeObjectAllocation = 1 << 2, }; typedef base::Flags<AllocationFlag> AllocationFlags; diff --git a/src/runtime/runtime-internal.cc b/src/runtime/runtime-internal.cc index 43c0a8b36d..aa8b3d091d 100644 --- a/src/runtime/runtime-internal.cc +++ b/src/runtime/runtime-internal.cc @@ -273,9 +273,9 @@ RUNTIME_FUNCTION(Runtime_AllocateInTargetSpace) { CONVERT_SMI_ARG_CHECKED(flags, 1); CHECK(IsAligned(size, kPointerSize)); CHECK(size > 0); - CHECK(size <= kMaxRegularHeapObjectSize); bool double_align = AllocateDoubleAlignFlag::decode(flags); AllocationSpace space = AllocateTargetSpace::decode(flags); + CHECK(size <= kMaxRegularHeapObjectSize || space == LO_SPACE); return *isolate->factory()->NewFillerObject(size, double_align, space); } diff --git a/test/mjsunit/regress/regress-670671.js b/test/mjsunit/regress/regress-670671.js new file mode 100644 index 0000000000..06925de5b9 --- /dev/null +++ b/test/mjsunit/regress/regress-670671.js @@ -0,0 +1,23 @@ +// Copyright 2016 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Trigger an infinite loop through RegExp.prototype[@@match], which results +// in unbounded growth of the results array. + +// Limit the number of iterations to avoid OOM while still triggering large +// object space allocation. +const min_ptr_size = 4; +const max_regular_heap_object_size = 507136; +const num_iterations = max_regular_heap_object_size / min_ptr_size; + +let i = 0; + +const re = /foo.bar/; +const RegExpPrototypeExec = RegExp.prototype.exec; +re.exec = (str) => { + return (i++ < num_iterations) ? RegExpPrototypeExec.call(re, str) : null; +}; +re.__defineGetter__("global", () => true); // Triggers infinite loop. + +"foo*bar".match(re); // Should not crash.