Commit 154f0cb3 authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[array] Refactor sort pre-processing into a single runtime function.

This CL consolidates CopyFromPrototype and RemoveArrayHoles into a
single runtime function. It also creates two small helper functions
that are needed in both pre-processing steps.

Additionally it removes the return value from CopyFromPrototype since
it is no longer needed (it was previously used by a sort post-
processing step that no longer exists).

Bug: v8:7382
Change-Id: I7f9b00c1bc639d2118fdecef9c3b45c2cf010310
Reviewed-on: https://chromium-review.googlesource.com/1051887
Commit-Queue: Simon Zünd <szuend@google.com>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53199}
parent d22b125a
......@@ -345,14 +345,13 @@ bool IntrinsicHasNoSideEffect(Runtime::FunctionId id) {
V(LoadLookupSlotForCall) \
/* Arrays */ \
V(ArraySpeciesConstructor) \
V(CopyFromPrototype) \
V(EstimateNumberOfElements) \
V(GetArrayKeys) \
V(HasComplexElements) \
V(HasFastPackedElements) \
V(NewArray) \
V(NormalizeElements) \
V(RemoveArrayHoles) \
V(PrepareElementsForSort) \
V(TrySliceSimpleNonFastElements) \
V(TypedArrayGetBuffer) \
/* Errors */ \
......
......@@ -803,23 +803,19 @@ function InnerArraySort(array, length, comparefn) {
if (length < 2) return array;
var is_array = IS_ARRAY(array);
var max_prototype_element;
if (!is_array) {
// For compatibility with JSC, we also sort elements inherited from
// the prototype chain on non-Array objects.
// We do this by copying them to this object and sorting only
// own elements. This is not very efficient, but sorting with
// inherited elements happens very, very rarely, if at all.
// The specification allows "implementation dependent" behavior
// if an element on the prototype chain has an element that
// might interact with sorting.
max_prototype_element = %CopyFromPrototype(array, length);
}
// %RemoveArrayHoles moves all non-undefined elements to the front of the
// array and moves the undefineds after that. Holes are removed.
var num_non_undefined = %RemoveArrayHoles(array, length);
// For compatibility with JSC, we also sort elements inherited from
// the prototype chain on non-Array objects.
// We do this by copying them to this object and sorting only
// own elements. This is not very efficient, but sorting with
// inherited elements happens very, very rarely, if at all.
// The specification allows "implementation dependent" behavior
// if an element on the prototype chain has an element that
// might interact with sorting.
//
// We also move all non-undefined elements to the front of the
// array and move the undefineds after that. Holes are removed.
// This happens for Array as well as non-Array objects.
var num_non_undefined = %PrepareElementsForSort(array, length);
QuickSort(array, 0, num_non_undefined);
......
......@@ -8896,6 +8896,18 @@ MaybeHandle<FixedArray> JSReceiver::GetOwnEntries(Handle<JSReceiver> object,
try_fast_path, true);
}
Handle<FixedArray> JSReceiver::GetOwnElementIndices(Isolate* isolate,
Handle<JSReceiver> receiver,
Handle<JSObject> object) {
KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
ALL_PROPERTIES);
accumulator.CollectOwnElementIndices(receiver, object);
Handle<FixedArray> keys =
accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
DCHECK(keys->ContainsSortedNumbers());
return keys;
}
bool Map::DictionaryElementsInPrototypeChainOnly() {
if (IsDictionaryElementsKind(elements_kind())) {
return false;
......@@ -10092,6 +10104,20 @@ Handle<FixedArray> FixedArray::SetAndGrow(Handle<FixedArray> array, int index,
return new_array;
}
bool FixedArray::ContainsSortedNumbers() {
for (int i = 1; i < length(); ++i) {
Object* a_obj = get(i - 1);
Object* b_obj = get(i);
if (!a_obj->IsNumber() || !b_obj->IsNumber()) return false;
uint32_t a = NumberToUint32(a_obj);
uint32_t b = NumberToUint32(b_obj);
if (a > b) return false;
}
return true;
}
void FixedArray::Shrink(int new_length) {
DCHECK(0 <= new_length && new_length <= length());
if (new_length < length()) {
......
......@@ -2262,6 +2262,9 @@ class JSReceiver: public HeapObject {
Handle<JSReceiver> object, PropertyFilter filter,
bool try_fast_path = true);
V8_WARN_UNUSED_RESULT static Handle<FixedArray> GetOwnElementIndices(
Isolate* isolate, Handle<JSReceiver> receiver, Handle<JSObject> object);
static const int kHashMask = PropertyArray::HashField::kMask;
// Layout description.
......
......@@ -127,6 +127,8 @@ class FixedArray : public FixedArrayBase {
inline Object** GetFirstElementAddress();
inline bool ContainsOnlySmisOrHoles();
// Returns true iff the elements are Numbers and sorted ascending.
bool ContainsSortedNumbers();
// Gives access to raw memory which stores the array's data.
inline Object** data_start();
......
This diff is collapsed.
......@@ -49,8 +49,7 @@ namespace internal {
F(MoveArrayContents, 2, 1) \
F(NewArray, -1 /* >= 3 */, 1) \
F(NormalizeElements, 1, 1) \
F(RemoveArrayHoles, 2, 1) \
F(CopyFromPrototype, 2, 1) \
F(PrepareElementsForSort, 2, 1) \
F(TransitionElementsKind, 2, 1) \
F(TrySliceSimpleNonFastElements, 3, 1)
......
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