Commit 37ff95ad authored by Irina Yatsenko's avatar Irina Yatsenko Committed by Commit Bot

Move empty elements canonicalization from call sites of

AllocateUninitializedJSArrayWithElements into the method.

Prior to the change, if the caller forgets to handle empty case on
their side, AllocateUninitializedJSArrayWithElements would allocate a
new empty FixedArray rather than return the canonical one. This refactor
shifts the burden of canonicalization from the callers to
AllocateUninitializedJSArrayWithElements.


Bug: v8:6777
Change-Id: I1246cb288861b65b51938414a454f21af78f8399
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1480330Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Irina Yatsenko <irinayat@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#60015}
parent f35ad6ec
...@@ -3822,6 +3822,30 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements( ...@@ -3822,6 +3822,30 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements(
CHECK_EQ(allocation_flags & ~kAllowLargeObjectAllocation, 0); CHECK_EQ(allocation_flags & ~kAllowLargeObjectAllocation, 0);
CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length)); CSA_SLOW_ASSERT(this, TaggedIsPositiveSmi(length));
TVARIABLE(JSArray, array);
TVARIABLE(FixedArrayBase, elements);
if (IsIntPtrOrSmiConstantZero(capacity, capacity_mode)) {
TNode<FixedArrayBase> empty_array = EmptyFixedArrayConstant();
array = AllocateJSArray(array_map, empty_array, length, allocation_site);
return {array.value(), empty_array};
}
Label out(this), empty(this), nonempty(this);
Branch(SmiEqual(ParameterToTagged(capacity, capacity_mode), SmiConstant(0)),
&empty, &nonempty);
BIND(&empty);
{
TNode<FixedArrayBase> empty_array = EmptyFixedArrayConstant();
array = AllocateJSArray(array_map, empty_array, length, allocation_site);
elements = empty_array;
Goto(&out);
}
BIND(&nonempty);
{
int base_size = JSArray::kSize; int base_size = JSArray::kSize;
if (allocation_site != nullptr) base_size += AllocationMemento::kSize; if (allocation_site != nullptr) base_size += AllocationMemento::kSize;
...@@ -3832,24 +3856,19 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements( ...@@ -3832,24 +3856,19 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements(
TNode<IntPtrT> size = TNode<IntPtrT> size =
ElementOffsetFromIndex(capacity, kind, capacity_mode, base_size); ElementOffsetFromIndex(capacity, kind, capacity_mode, base_size);
TVARIABLE(JSArray, array);
TVARIABLE(FixedArrayBase, elements);
Label out(this);
// For very large arrays in which the requested allocation exceeds the // For very large arrays in which the requested allocation exceeds the
// maximal size of a regular heap object, we cannot use the allocation // maximal size of a regular heap object, we cannot use the allocation
// folding trick. Instead, we first allocate the elements in large object // folding trick. Instead, we first allocate the elements in large object
// space, and then allocate the JSArray (and possibly the allocation memento) // space, and then allocate the JSArray (and possibly the allocation
// in new space. // memento) in new space.
if (allocation_flags & kAllowLargeObjectAllocation) { if (allocation_flags & kAllowLargeObjectAllocation) {
Label next(this); Label next(this);
GotoIf(IsRegularHeapObjectSize(size), &next); GotoIf(IsRegularHeapObjectSize(size), &next);
CSA_CHECK(this, IsValidFastJSArrayCapacity(capacity, capacity_mode)); CSA_CHECK(this, IsValidFastJSArrayCapacity(capacity, capacity_mode));
// Allocate and initialize the elements first. Full initialization is needed // Allocate and initialize the elements first. Full initialization is
// because the upcoming JSArray allocation could trigger GC. // needed because the upcoming JSArray allocation could trigger GC.
elements = elements =
AllocateFixedArray(kind, capacity, capacity_mode, allocation_flags); AllocateFixedArray(kind, capacity, capacity_mode, allocation_flags);
...@@ -3862,8 +3881,8 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements( ...@@ -3862,8 +3881,8 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements(
} }
// The JSArray and possibly allocation memento next. Note that // The JSArray and possibly allocation memento next. Note that
// allocation_flags are *not* passed on here and the resulting JSArray will // allocation_flags are *not* passed on here and the resulting JSArray
// always be in new space. // will always be in new space.
array = array =
AllocateJSArray(array_map, elements.value(), length, allocation_site); AllocateJSArray(array_map, elements.value(), length, allocation_site);
...@@ -3894,6 +3913,7 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements( ...@@ -3894,6 +3913,7 @@ CodeStubAssembler::AllocateUninitializedJSArrayWithElements(
StoreObjectFieldNoWriteBarrier(elements.value(), FixedArray::kLengthOffset, StoreObjectFieldNoWriteBarrier(elements.value(), FixedArray::kLengthOffset,
capacity_smi); capacity_smi);
Goto(&out); Goto(&out);
}
BIND(&out); BIND(&out);
return {array.value(), elements.value()}; return {array.value(), elements.value()};
...@@ -3929,53 +3949,18 @@ TNode<JSArray> CodeStubAssembler::AllocateJSArray( ...@@ -3929,53 +3949,18 @@ TNode<JSArray> CodeStubAssembler::AllocateJSArray(
TNode<JSArray> array; TNode<JSArray> array;
TNode<FixedArrayBase> elements; TNode<FixedArrayBase> elements;
int capacity_as_constant;
if (IsIntPtrOrSmiConstantZero(capacity, capacity_mode)) {
// Array is empty. Use the shared empty fixed array instead of allocating a
// new one.
TNode<FixedArrayBase> empty_fixed_array =
CAST(LoadRoot(RootIndex::kEmptyFixedArray));
array =
AllocateJSArray(array_map, empty_fixed_array, length, allocation_site);
} else if (TryGetIntPtrOrSmiConstantValue(capacity, &capacity_as_constant,
capacity_mode)) {
CHECK_GT(capacity_as_constant, 0);
// Allocate both array and elements object, and initialize the JSArray.
std::tie(array, elements) = AllocateUninitializedJSArrayWithElements( std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
kind, array_map, length, allocation_site, capacity, capacity_mode, kind, array_map, length, allocation_site, capacity, capacity_mode,
allocation_flags); allocation_flags);
// Fill in the elements with holes.
FillFixedArrayWithValue(kind, elements,
IntPtrOrSmiConstant(0, capacity_mode), capacity,
RootIndex::kTheHoleValue, capacity_mode);
} else {
Label out(this), empty(this), nonempty(this);
TVARIABLE(JSArray, var_array);
Branch(SmiEqual(ParameterToTagged(capacity, capacity_mode), SmiConstant(0)), Label out(this), nonempty(this);
&empty, &nonempty);
BIND(&empty); Branch(SmiEqual(ParameterToTagged(capacity, capacity_mode), SmiConstant(0)),
{ &out, &nonempty);
// Array is empty. Use the shared empty fixed array instead of allocating
// a new one.
TNode<FixedArrayBase> empty_fixed_array =
CAST(LoadRoot(RootIndex::kEmptyFixedArray));
var_array = AllocateJSArray(array_map, empty_fixed_array, length,
allocation_site);
Goto(&out);
}
BIND(&nonempty); BIND(&nonempty);
{ {
// Allocate both array and elements object, and initialize the JSArray.
TNode<JSArray> array;
std::tie(array, elements) = AllocateUninitializedJSArrayWithElements(
kind, array_map, length, allocation_site, capacity, capacity_mode,
allocation_flags);
var_array = array;
// Fill in the elements with holes.
FillFixedArrayWithValue(kind, elements, FillFixedArrayWithValue(kind, elements,
IntPtrOrSmiConstant(0, capacity_mode), capacity, IntPtrOrSmiConstant(0, capacity_mode), capacity,
RootIndex::kTheHoleValue, capacity_mode); RootIndex::kTheHoleValue, capacity_mode);
...@@ -3983,9 +3968,6 @@ TNode<JSArray> CodeStubAssembler::AllocateJSArray( ...@@ -3983,9 +3968,6 @@ TNode<JSArray> CodeStubAssembler::AllocateJSArray(
} }
BIND(&out); BIND(&out);
array = var_array.value();
}
return array; return array;
} }
......
...@@ -28,6 +28,9 @@ ...@@ -28,6 +28,9 @@
// Test ES5 section 15.2.3.4 Object.getOwnPropertyNames. // Test ES5 section 15.2.3.4 Object.getOwnPropertyNames.
// Check simple cases. // Check simple cases.
var obj = {};
assertEquals(0, Object.getOwnPropertyNames(obj).length);
var obj = { a: 1, b: 2}; var obj = { a: 1, b: 2};
var propertyNames = Object.getOwnPropertyNames(obj); var propertyNames = Object.getOwnPropertyNames(obj);
propertyNames.sort(); propertyNames.sort();
...@@ -52,6 +55,13 @@ assertEquals("a", propertyNames[0]); ...@@ -52,6 +55,13 @@ assertEquals("a", propertyNames[0]);
assertEquals("c", propertyNames[1]); assertEquals("c", propertyNames[1]);
// Check that non-enumerable properties are being returned. // Check that non-enumerable properties are being returned.
var obj = {};
Object.defineProperty(obj, 'x', {
value: 1,
enumerable: false
});
assertEquals(1, Object.getOwnPropertyNames(obj).length);
var propertyNames = Object.getOwnPropertyNames([1, 2]); var propertyNames = Object.getOwnPropertyNames([1, 2]);
propertyNames.sort(); propertyNames.sort();
assertEquals(3, propertyNames.length); assertEquals(3, propertyNames.length);
......
...@@ -4,6 +4,31 @@ ...@@ -4,6 +4,31 @@
// Flags: --allow-natives-syntax // Flags: --allow-natives-syntax
// Ensure empty keys are handled properly
(function() {
const a = {};
let k = Object.keys(a);
%HeapObjectVerify(k);
assertEquals(0, k.length);
})();
// Ensure non-enumerable keys are handled properly
(function() {
const a = {};
Object.defineProperty(a, 'x', {
value: 1,
enumerable: false
});
let k = Object.keys(a);
%HeapObjectVerify(k);
assertEquals(0, k.length);
a.y = 2;
k = Object.keys(a);
%HeapObjectVerify(k);
assertEquals(1, k.length);
})();
// Ensure that mutation of the Object.keys result doesn't affect the // Ensure that mutation of the Object.keys result doesn't affect the
// enumeration cache for fast-mode objects. // enumeration cache for fast-mode objects.
(function() { (function() {
......
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