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

[array] Add fastpath for dictionary elements to Array.p.sort

R=cbruni@chromium.org, jgruber@chromium.org

Bug: v8:7382
Change-Id: I45f2517afa8ecb3ddb1f77f845e9ce88f69d4eef
Reviewed-on: https://chromium-review.googlesource.com/1092500Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Simon Zünd <szuend@google.com>
Cr-Commit-Position: refs/heads/master@{#53788}
parent eaf03c0c
......@@ -10,6 +10,7 @@ module array {
type FastPackedSmiElements;
type FastSmiOrObjectElements;
type FastDoubleElements;
type DictionaryElements;
macro Load<ElementsAccessor : type>(
context: Context, receiver: Object, index: Smi): Object labels Bailout {
......@@ -38,6 +39,16 @@ module array {
return AllocateHeapNumberWithValue(value);
}
Load<DictionaryElements>(
context: Context, elements: Object, index: Smi): Object labels Bailout {
let dictionary: NumberDictionary = unsafe_cast<NumberDictionary>(elements);
let intptr_index: intptr = convert<intptr>(index);
let value: Object =
BasicLoadNumberDictionaryElement(dictionary, intptr_index)
otherwise Bailout, Bailout;
return value;
}
macro Store<ElementsAccessor : type>(
context: Context, receiver: Object, index: Smi, value: Object) {
SetProperty(context, receiver, index, value, kStrict);
......@@ -70,6 +81,21 @@ module array {
return UnsafeCastObjectToCompareBuiltinFn(o);
}
Store<DictionaryElements>(
context: Context, elements: Object, index: Smi, value: Object) {
try {
let dictionary: NumberDictionary =
unsafe_cast<NumberDictionary>(elements);
let intptr_index: intptr = convert<intptr>(index);
BasicStoreNumberDictionaryElement(dictionary, intptr_index, value)
otherwise Fail, Fail;
return;
}
label Fail {
unreachable;
}
}
builtin SortCompareDefault(
context: Context, comparefn: Object, x: Object, y: Object): Number {
assert(comparefn == Undefined);
......@@ -136,6 +162,13 @@ module array {
return true;
}
CanUseSameAccessor<DictionaryElements>(
context: Context, receiver: Object, initialReceiverMap: Object,
initialReceiverLength: Number): bool {
let obj: JSReceiver = unsafe_cast<JSReceiver>(receiver);
return obj.map == initialReceiverMap;
}
macro CallCompareFn<E : type>(
context: Context, receiver: Object, initialReceiverMap: Object,
initialReceiverLength: Number, userCmpFn: Object,
......@@ -155,6 +188,9 @@ module array {
to: Smi, userCmpFn: Object, sortCompare: CompareBuiltinFn)
labels Bailout {
for (let i: Smi = from + 1; i < to; ++i) {
assert(CanUseSameAccessor<E>(
context, receiver, initialReceiverMap, initialReceiverLength));
let element: Object = Load<E>(context, elements, i) otherwise Bailout;
let j: Smi = i - 1;
for (; j >= from; --j) {
......@@ -282,6 +318,8 @@ module array {
// Move pivot element to a place on the left.
Swap<E>(context, elements, from + 1, third_index, v1) otherwise Bailout;
assert(CanUseSameAccessor<E>(
context, receiver, initialReceiverMap, initialReceiverLength));
return v1;
}
......@@ -350,6 +388,9 @@ module array {
// Start looking for high_start to find the first value that is
// smaller than pivot.
while (order > 0) {
assert(CanUseSameAccessor<E>(
context, receiver, initialReceiverMap, initialReceiverLength));
high_start--;
if (high_start == idx) {
break_for = true;
......@@ -475,6 +516,7 @@ module array {
// TODO(szuend): Investigate performance tradeoff of skipping this step
// for PACKED_* and handling Undefineds during sorting.
let nofNonUndefined: Smi = PrepareElementsForSort(context, obj, len);
assert(a.map == map);
sort_state[kInitialReceiverLengthIdx()] = len;
sort_state[kElementsIdx()] = a.elements;
......@@ -502,9 +544,22 @@ module array {
let nofNonUndefined: Smi = PrepareElementsForSort(context, obj, len);
sort_state[kInitialReceiverLengthIdx()] = len;
sort_state[kElementsIdx()] = obj;
sort_state[kRandomStateIdx()] = nofNonUndefined;
// Reload the map, PrepareElementsForSort might have changed the
// elements kind.
map = obj.map;
if (map.elements_kind == DICTIONARY_ELEMENTS && IsExtensibleMap(map) &&
!IsCustomElementsReceiverInstanceType(map.instance_type)) {
let jsobj: JSObject = unsafe_cast<JSObject>(obj);
sort_state[kElementsIdx()] = jsobj.elements;
ArrayQuickSort<DictionaryElements>(
context, sort_state, 0, nofNonUndefined);
return receiver;
}
sort_state[kElementsIdx()] = obj;
ArrayQuickSort<GenericElementsAccessor>(
context, sort_state, 0, nofNonUndefined);
}
......
......@@ -48,6 +48,7 @@ type FixedTypedArrayBase extends FixedArrayBase generates
'TNode<FixedTypedArrayBase>';
type FixedTypedArray extends FixedTypedArrayBase generates
'TNode<FixedTypedArray>';
type NumberDictionary extends HeapObject generates 'TNode<NumberDictionary>';
type JSArrayBuffer extends JSObject generates 'TNode<JSArrayBuffer>';
type JSArrayBufferView extends JSObject generates 'TNode<JSArrayBufferView>';
......@@ -73,6 +74,7 @@ const PACKED_ELEMENTS: constexpr ElementsKind = 'PACKED_ELEMENTS';
const HOLEY_ELEMENTS: constexpr ElementsKind = 'HOLEY_ELEMENTS';
const PACKED_DOUBLE_ELEMENTS: constexpr ElementsKind = 'PACKED_DOUBLE_ELEMENTS';
const HOLEY_DOUBLE_ELEMENTS: constexpr ElementsKind = 'HOLEY_DOUBLE_ELEMENTS';
const DICTIONARY_ELEMENTS: constexpr ElementsKind = 'DICTIONARY_ELEMENTS';
const UINT8_ELEMENTS: constexpr ElementsKind = 'UINT8_ELEMENTS';
const INT8_ELEMENTS: constexpr ElementsKind = 'INT8_ELEMENTS';
......@@ -279,7 +281,7 @@ extern macro ConvertFixedArrayBaseToFixedDoubleArray(FixedArrayBase):
FixedDoubleArray labels CastError;
extern macro TaggedToNumber(Object): Number labels CastError;
macro cast<A: type>(o: Object): A labels CastError;
macro cast<A : type>(o: Object): A labels CastError;
cast<Number>(o: Object): Number labels CastError {
return TaggedToNumber(o) otherwise CastError;
}
......@@ -298,7 +300,7 @@ cast<Callable>(o: Object): Callable labels CastError {
cast<JSArray>(o: Object): JSArray labels CastError {
return TaggedToJSArray(o) otherwise CastError;
}
macro cast<A: type>(o: FixedArrayBase): A labels CastError;
macro cast<A : type>(o: FixedArrayBase): A labels CastError;
cast<FixedArray>(o: FixedArrayBase): FixedArray labels CastError {
return ConvertFixedArrayBaseToFixedArray(o) otherwise CastError;
}
......@@ -335,7 +337,7 @@ extern macro BoolConstant(constexpr bool): bool;
extern macro LanguageModeConstant(constexpr LanguageMode): LanguageMode;
extern macro Int32Constant(constexpr ElementsKind): ElementsKind;
macro from_constexpr<A: type>(o: constexpr int31): A;
macro from_constexpr<A : type>(o: constexpr int31): A;
from_constexpr<intptr>(i: constexpr int31): intptr {
return IntPtrConstant(i);
}
......@@ -351,7 +353,7 @@ from_constexpr<Smi>(i: constexpr int31): Smi {
from_constexpr<Number>(i: constexpr int31): Number {
return SmiConstant(i);
}
macro from_constexpr<A: type>(o: constexpr int32): A;
macro from_constexpr<A : type>(o: constexpr int32): A;
from_constexpr<intptr>(i: constexpr int32): intptr {
return IntPtrConstant(i);
}
......@@ -364,24 +366,24 @@ from_constexpr<word32>(i: constexpr int32): word32 {
from_constexpr<Number>(i: constexpr int32): Number {
return NumberConstant(i);
}
macro from_constexpr<A: type>(o: constexpr float64): A;
macro from_constexpr<A : type>(o: constexpr float64): A;
from_constexpr<Number>(f: constexpr float64): Number {
return NumberConstant(f);
}
macro from_constexpr<A: type>(b: constexpr bool): A;
macro from_constexpr<A : type>(b: constexpr bool): A;
from_constexpr<bool>(b: constexpr bool): bool {
return BoolConstant(b);
}
macro from_constexpr<A: type>(l: constexpr LanguageMode): A;
macro from_constexpr<A : type>(l: constexpr LanguageMode): A;
from_constexpr<LanguageMode>(b: constexpr LanguageMode): LanguageMode {
return LanguageModeConstant(b);
}
macro from_constexpr<A: type>(e: constexpr ElementsKind): A;
macro from_constexpr<A : type>(e: constexpr ElementsKind): A;
from_constexpr<ElementsKind>(e: constexpr ElementsKind): ElementsKind {
return Int32Constant(e);
}
macro convert<A: type>(i: int32): A;
macro convert<A : type>(i: int32): A;
convert<Number>(i: int32): Number {
return ChangeInt32ToTagged(i);
}
......@@ -394,7 +396,7 @@ convert<intptr>(i: int32): intptr {
convert<Smi>(i: int32): Smi {
return SmiFromInt32(i);
}
macro convert<A: type>(ui: uint32): A;
macro convert<A : type>(ui: uint32): A;
convert<Number>(ui: uint32): Number {
return ChangeUint32ToTagged(ui);
}
......@@ -408,7 +410,7 @@ convert<uint32>(word: word32): uint32 {
convert<uintptr>(word: word32): uintptr {
return ChangeUint32ToWord(word);
}
macro convert<A: type>(i: intptr): A;
macro convert<A : type>(i: intptr): A;
convert<int32>(i: intptr): int32 {
return TruncateIntPtrToInt32(i);
}
......@@ -422,22 +424,22 @@ macro convert<A: type>(ui: uintptr): A;
convert<intptr>(ui: uintptr): intptr {
return Signed(ui);
}
macro convert<A: type>(s: Smi): A;
macro convert<A : type>(s: Smi): A;
convert<intptr>(s: Smi): intptr {
return SmiUntag(s);
}
convert<int32>(s: Smi): int32 {
return SmiToInt32(s);
}
macro convert<A: type>(h: HeapNumber): A;
macro convert<A : type>(h: HeapNumber): A;
convert<float64>(h: HeapNumber): float64 {
return LoadHeapNumberValue(h);
}
macro convert<A: type>(n: Number): A;
macro convert<A : type>(n: Number): A;
convert<float64>(n: Number): float64 {
return ChangeNumberToFloat64(n);
}
macro convert<A: type>(f: float32): A;
macro convert<A : type>(f: float32): A;
convert<float64>(f: float32): float64 {
return ChangeFloat32ToFloat64(f);
}
......@@ -452,12 +454,15 @@ extern macro UnsafeCastObjectToNumber(Object): Number;
extern macro UnsafeCastObjectToHeapObject(Object): HeapObject;
extern macro UnsafeCastObjectToJSArray(Object): JSArray;
extern macro UnsafeCastObjectToFixedTypedArrayBase(Object): FixedTypedArrayBase;
extern macro UnsafeCastObjectToNumberDictionary(Object): NumberDictionary;
extern macro UnsafeCastObjectToJSReceiver(Object): JSReceiver;
extern macro UnsafeCastObjectToJSObject(Object): JSObject;
macro unsafe_cast<A: type>(n: Number): A;
macro unsafe_cast<A : type>(n: Number): A;
unsafe_cast<HeapNumber>(n: Number): HeapNumber {
return UnsafeCastNumberToHeapNumber(n);
}
macro unsafe_cast<A: type>(o: Object): A;
macro unsafe_cast<A : type>(o: Object): A;
unsafe_cast<FixedArray>(o: Object): FixedArray {
return UnsafeCastObjectToFixedArray(o);
}
......@@ -485,6 +490,15 @@ unsafe_cast<JSArray>(o: Object): JSArray {
unsafe_cast<FixedTypedArrayBase>(o: Object): FixedTypedArrayBase {
return UnsafeCastObjectToFixedTypedArrayBase(o);
}
unsafe_cast<NumberDictionary>(o: Object): NumberDictionary {
return UnsafeCastObjectToNumberDictionary(o);
}
unsafe_cast<JSReceiver>(o: Object): JSReceiver {
return UnsafeCastObjectToJSReceiver(o);
}
unsafe_cast<JSObject>(o: Object): JSObject {
return UnsafeCastObjectToJSObject(o);
}
extern macro BranchIfFastJSArray(Object, Context): never labels Taken, NotTaken;
extern macro BranchIfNotFastJSArray(Object, Context): never labels Taken,
......@@ -526,6 +540,8 @@ extern operator
extern operator
'[]=' macro StoreFixedArrayElementSmi(FixedArray, Smi, Object): void;
extern operator '.instance_type' macro LoadMapInstanceType(Map): int32;
extern macro LoadFixedDoubleArrayElement(FixedDoubleArray, Smi): float64;
extern macro Float64SilenceNaN(float64): float64;
......@@ -536,6 +552,13 @@ macro StoreFixedDoubleArrayElementWithSmiIndex(
StoreFixedDoubleArrayElement(array, index, value, SMI_PARAMETERS);
}
extern macro BasicLoadNumberDictionaryElement(NumberDictionary, intptr):
Object labels NotData,
IfHole;
extern macro BasicStoreNumberDictionaryElement(NumberDictionary, intptr, Object)
labels Fail,
IfHole;
extern macro IsFastElementsKind(ElementsKind): bool;
extern macro IsDoubleElementsKind(ElementsKind): bool;
extern macro IsFastSmiOrTaggedElementsKind(ElementsKind): bool;
......@@ -613,6 +636,8 @@ extern macro IsJSArray(HeapObject): bool;
extern macro TaggedIsCallable(Object): bool;
extern macro IsDetachedBuffer(JSArrayBuffer): bool;
extern macro IsHeapNumber(HeapObject): bool;
extern macro IsExtensibleMap(Map): bool;
extern macro IsCustomElementsReceiverInstanceType(int32): bool;
// Return true iff number is NaN.
macro NumberIsNaN(number: Number): bool {
......
......@@ -7331,7 +7331,7 @@ void CodeStubAssembler::NumberDictionaryLookup(
}
}
TNode<Object> CodeStubAssembler::LoadNumberDictionaryElement(
TNode<Object> CodeStubAssembler::BasicLoadNumberDictionaryElement(
TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index,
Label* not_data, Label* if_hole) {
TVARIABLE(IntPtrT, var_entry);
......@@ -7347,10 +7347,34 @@ TNode<Object> CodeStubAssembler::LoadNumberDictionaryElement(
TNode<Uint32T> kind = DecodeWord32<PropertyDetails::KindField>(details);
// TODO(jkummerow): Support accessors without missing?
GotoIfNot(Word32Equal(kind, Int32Constant(kData)), not_data);
// Finally, load athe value.
// Finally, load the value.
return LoadValueByKeyIndex<NumberDictionary>(dictionary, index);
}
void CodeStubAssembler::BasicStoreNumberDictionaryElement(
TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index,
TNode<Object> value, Label* fail, Label* if_hole) {
TVARIABLE(IntPtrT, var_entry);
Label if_found(this);
NumberDictionaryLookup(dictionary, intptr_index, &if_found, &var_entry,
if_hole);
BIND(&if_found);
// Check that the value is a data property.
TNode<IntPtrT> index = EntryToIndex<NumberDictionary>(var_entry.value());
TNode<Uint32T> details =
LoadDetailsByKeyIndex<NumberDictionary>(dictionary, index);
TNode<Uint32T> kind = DecodeWord32<PropertyDetails::KindField>(details);
// TODO(jkummerow): Support accessors without missing?
GotoIfNot(Word32Equal(kind, Int32Constant(kData)), fail);
// Check that the property is writeable.
GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask), fail);
// Finally, store the value.
StoreValueByKeyIndex<NumberDictionary>(dictionary, index, value);
}
template <class Dictionary>
void CodeStubAssembler::FindInsertionEntry(TNode<Dictionary> dictionary,
TNode<Name> key,
......
......@@ -354,6 +354,19 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
return p_o;
}
TNode<NumberDictionary> UnsafeCastObjectToNumberDictionary(
TNode<Object> p_o) {
return CAST(p_o);
}
TNode<JSReceiver> UnsafeCastObjectToJSReceiver(TNode<Object> p_o) {
return CAST(p_o);
}
TNode<JSObject> UnsafeCastObjectToJSObject(TNode<Object> p_o) {
return CAST(p_o);
}
Node* MatchesParameterMode(Node* value, ParameterMode mode);
#define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \
......@@ -2127,9 +2140,13 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
TVariable<IntPtrT>* var_entry,
Label* if_not_found);
TNode<Object> LoadNumberDictionaryElement(TNode<NumberDictionary> dictionary,
TNode<IntPtrT> intptr_index,
Label* not_data, Label* if_hole);
TNode<Object> BasicLoadNumberDictionaryElement(
TNode<NumberDictionary> dictionary, TNode<IntPtrT> intptr_index,
Label* not_data, Label* if_hole);
void BasicStoreNumberDictionaryElement(TNode<NumberDictionary> dictionary,
TNode<IntPtrT> intptr_index,
TNode<Object> value, Label* fail,
Label* if_hole);
template <class Dictionary>
void FindInsertionEntry(TNode<Dictionary> dictionary, TNode<Name> key,
......
......@@ -1801,7 +1801,7 @@ void AccessorAssembler::EmitElementLoad(
Comment("dictionary elements");
GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
TNode<Object> value = LoadNumberDictionaryElement(
TNode<Object> value = BasicLoadNumberDictionaryElement(
CAST(elements), intptr_index, miss, if_hole);
exit_point->Return(value);
}
......
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