Commit bd9ef0f3 authored by Mike Stanton's avatar Mike Stanton Committed by Commit Bot

[Torque] Reduce code size by combining FixedArray/FixedDoubleArray paths

This CL reduces the instruction size of Array.prototype.every and some
by ~20%. Should performance allow it we could do the same for other
array builtins. We attach a boolean to the FastJSArrayWitness that
remembers if it's dealing with a FixedArray or a FixedDoubleArray.
We have to check this in the loop, but it is likely that reduced
code size more than pays for the extra check, since the loop will
be dominated by the call to the users callback function.

BUG: v8:7672
Change-Id: Id3bab2b163d7ba73424250d8bb194712909cd37e
Reviewed-on: https://chromium-review.googlesource.com/c/1484293Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59835}
parent 6d640b9b
......@@ -83,51 +83,30 @@ namespace array {
return True;
}
transitioning macro
EveryVisitAllElements<FixedArrayType: type>(implicit context: Context)(
o: FastJSArray, len: Smi, callbackfn: Callable,
thisArg: Object): Boolean labels Bailout(Smi) {
transitioning macro FastArrayEvery(implicit context: Context)(
o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
labels Bailout(Smi) {
let k: Smi = 0;
let fastO = FastJSArrayWitness{o};
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
let fastO: FastJSArray = Cast<FastJSArray>(o) otherwise goto Bailout(k);
let fastOW = FastJSArrayWitness{fastO};
// Build a fast loop over the smi array.
for (; k < len; k++) {
fastO.Recheck() otherwise goto Bailout(k);
for (; k < smiLen; k++) {
fastOW.Recheck() otherwise goto Bailout(k);
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastO.Get().length) goto Bailout(k);
try {
const value: Object = LoadElementNoHole<FixedArrayType>(fastO.Get(), k)
otherwise FoundHole;
if (k >= fastOW.Get().length) goto Bailout(k);
const value: Object = fastOW.LoadElementNoHole(k) otherwise continue;
const result: Object =
Call(context, callbackfn, thisArg, value, k, fastO.Get());
Call(context, callbackfn, thisArg, value, k, fastOW.Get());
if (!ToBoolean(result)) {
return False;
}
}
label FoundHole {}
}
return True;
}
transitioning macro FastArrayEvery(implicit context: Context)(
o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
labels Bailout(Smi) {
let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k);
const elementsKind: ElementsKind = fastO.map.elements_kind;
if (IsElementsKindLessThanOrEqual(elementsKind, HOLEY_ELEMENTS)) {
return EveryVisitAllElements<FixedArray>(
fastO, smiLen, callbackfn, thisArg) otherwise Bailout;
}
assert(IsDoubleElementsKind(elementsKind));
return EveryVisitAllElements<FixedDoubleArray>(
fastO, smiLen, callbackfn, thisArg) otherwise Bailout;
}
// https://tc39.github.io/ecma262/#sec-array.prototype.every
transitioning javascript builtin
ArrayEvery(implicit context: Context)(receiver: Object, ...arguments):
......
......@@ -83,52 +83,30 @@ namespace array {
return False;
}
transitioning macro
SomeVisitAllElements<FixedArrayType: type>(implicit context: Context)(
o: FastJSArray, len: Smi, callbackfn: Callable, thisArg: Object): Boolean
transitioning macro FastArraySome(implicit context: Context)(
o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
labels Bailout(Smi) {
let k: Smi = 0;
let fastO = FastJSArrayWitness{o};
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k);
let fastOW = FastJSArrayWitness{fastO};
// Build a fast loop over the smi array.
for (; k < len; k++) {
fastO.Recheck() otherwise goto Bailout(k);
for (; k < smiLen; k++) {
fastOW.Recheck() otherwise goto Bailout(k);
// Ensure that we haven't walked beyond a possibly updated length.
if (k >= fastO.Get().length) goto Bailout(k);
try {
const value: Object = LoadElementNoHole<FixedArrayType>(fastO.Get(), k)
otherwise FoundHole;
if (k >= fastOW.Get().length) goto Bailout(k);
const value: Object = fastOW.LoadElementNoHole(k) otherwise continue;
const result: Object =
Call(context, callbackfn, thisArg, value, k, fastO.Get());
Call(context, callbackfn, thisArg, value, k, fastOW.Get());
if (ToBoolean(result)) {
return True;
}
}
label FoundHole {}
}
return False;
}
transitioning macro FastArraySome(implicit context: Context)(
o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Object
labels Bailout(Smi) {
let k: Smi = 0;
const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k);
const elementsKind: ElementsKind = fastO.map.elements_kind;
if (IsElementsKindLessThanOrEqual(elementsKind, HOLEY_ELEMENTS)) {
return SomeVisitAllElements<FixedArray>(
fastO, smiLen, callbackfn, thisArg)
otherwise Bailout;
}
assert(IsDoubleElementsKind(elementsKind));
return SomeVisitAllElements<FixedDoubleArray>(
fastO, smiLen, callbackfn, thisArg) otherwise Bailout;
}
// https://tc39.github.io/ecma262/#sec-array.prototype.some
transitioning javascript builtin
ArraySome(implicit context: Context)(receiver: Object, ...arguments): Object {
......
......@@ -935,33 +935,6 @@ Cast<FastJSArray>(implicit context: Context)(o: HeapObject): FastJSArray
return %RawDownCast<FastJSArray>(o);
}
struct FastJSArrayWitness {
constructor(array: FastJSArray) {
this.stable = this.unstable = array;
this.map = array.map;
}
Get(): FastJSArray {
return this.unstable;
}
Recheck() labels CastError {
if (this.stable.map != this.map) goto CastError;
// We don't need to check elements kind or whether the prototype
// has changed away from the default JSArray prototype, because
// if the map remains the same then those properties hold.
//
// However, we have to make sure there are no elements in the
// prototype chain.
if (IsNoElementsProtectorCellInvalid()) goto CastError;
this.unstable = %RawDownCast<FastJSArray>(this.stable);
}
stable: JSArray;
unstable: FastJSArray;
map: Map;
}
Cast<FastJSArrayForCopy>(implicit context: Context)(o: HeapObject):
FastJSArrayForCopy
labels CastError {
......@@ -1503,6 +1476,47 @@ LoadElementNoHole<FixedDoubleArray>(implicit context: Context)(
}
}
struct FastJSArrayWitness {
constructor(array: FastJSArray) {
this.stable = this.unstable = array;
this.map = array.map;
let kind = array.map.elements_kind;
this.hasDoubles = !IsElementsKindLessThanOrEqual(kind, HOLEY_ELEMENTS);
}
Get(): FastJSArray {
return this.unstable;
}
Recheck() labels CastError {
if (this.stable.map != this.map) goto CastError;
// We don't need to check elements kind or whether the prototype
// has changed away from the default JSArray prototype, because
// if the map remains the same then those properties hold.
//
// However, we have to make sure there are no elements in the
// prototype chain.
if (IsNoElementsProtectorCellInvalid()) goto CastError;
this.unstable = %RawDownCast<FastJSArray>(this.stable);
}
LoadElementNoHole(implicit context: Context)(k: Smi): Object
labels FoundHole {
if (this.hasDoubles) {
return LoadElementNoHole<FixedDoubleArray>(this.unstable, k)
otherwise FoundHole;
} else {
return LoadElementNoHole<FixedArray>(this.unstable, k)
otherwise FoundHole;
}
}
stable: JSArray;
unstable: FastJSArray;
map: Map;
hasDoubles: bool;
}
extern macro TransitionElementsKind(
JSObject, Map, constexpr ElementsKind,
constexpr ElementsKind): void labels Bailout;
......
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