mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-03-03 15:26:07 +00:00
Bug 1344477 - Part 2: Optimize Array.prototype.splice with JSOP_NORVCALL. r=jandem
This commit is contained in:
parent
7f556ef14e
commit
32cff5d448
@ -4666,19 +4666,6 @@ CodeGenerator::visitApplyArrayGeneric(LApplyArrayGeneric* apply)
|
||||
emitApplyGeneric(apply);
|
||||
}
|
||||
|
||||
typedef bool (*ArraySpliceDenseFn)(JSContext*, HandleObject, uint32_t, uint32_t);
|
||||
static const VMFunction ArraySpliceDenseInfo =
|
||||
FunctionInfo<ArraySpliceDenseFn>(ArraySpliceDense, "ArraySpliceDense");
|
||||
|
||||
void
|
||||
CodeGenerator::visitArraySplice(LArraySplice* lir)
|
||||
{
|
||||
pushArg(ToRegister(lir->getDeleteCount()));
|
||||
pushArg(ToRegister(lir->getStart()));
|
||||
pushArg(ToRegister(lir->getObject()));
|
||||
callVM(ArraySpliceDenseInfo, lir);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitBail(LBail* lir)
|
||||
{
|
||||
|
@ -258,7 +258,6 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||
void emitSetPropertyPolymorphic(LInstruction* lir, Register obj,
|
||||
Register scratch, const ConstantOrRegister& value);
|
||||
void visitSetPropertyPolymorphicV(LSetPropertyPolymorphicV* ins);
|
||||
void visitArraySplice(LArraySplice* splice);
|
||||
void visitSetPropertyPolymorphicT(LSetPropertyPolymorphicT* ins);
|
||||
void visitAbsI(LAbsI* lir);
|
||||
void visitAtan2D(LAtan2D* lir);
|
||||
|
@ -15,7 +15,6 @@
|
||||
_(ArrayShift) \
|
||||
_(ArrayPush) \
|
||||
_(ArraySlice) \
|
||||
_(ArraySplice) \
|
||||
\
|
||||
_(AtomicsCompareExchange) \
|
||||
_(AtomicsExchange) \
|
||||
|
@ -627,7 +627,6 @@ class IonBuilder
|
||||
InliningResult inlineArrayPush(CallInfo& callInfo);
|
||||
InliningResult inlineArraySlice(CallInfo& callInfo);
|
||||
InliningResult inlineArrayJoin(CallInfo& callInfo);
|
||||
InliningResult inlineArraySplice(CallInfo& callInfo);
|
||||
|
||||
// Math natives.
|
||||
InliningResult inlineMathAbs(CallInfo& callInfo);
|
||||
|
@ -655,16 +655,6 @@ LIRGenerator::visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* assertion
|
||||
MOZ_CRASH("AssertRecoveredOnBailout nodes are always recovered on bailouts.");
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitArraySplice(MArraySplice* ins)
|
||||
{
|
||||
LArraySplice* lir = new(alloc()) LArraySplice(useRegisterAtStart(ins->object()),
|
||||
useRegisterAtStart(ins->start()),
|
||||
useRegisterAtStart(ins->deleteCount()));
|
||||
add(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitGetDynamicName(MGetDynamicName* ins)
|
||||
{
|
||||
|
@ -107,7 +107,6 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitCall(MCall* call);
|
||||
void visitApplyArgs(MApplyArgs* apply);
|
||||
void visitApplyArray(MApplyArray* apply);
|
||||
void visitArraySplice(MArraySplice* splice);
|
||||
void visitBail(MBail* bail);
|
||||
void visitUnreachable(MUnreachable* unreachable);
|
||||
void visitEncodeSnapshot(MEncodeSnapshot* ins);
|
||||
|
@ -87,8 +87,6 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
|
||||
return inlineArrayPush(callInfo);
|
||||
case InlinableNative::ArraySlice:
|
||||
return inlineArraySlice(callInfo);
|
||||
case InlinableNative::ArraySplice:
|
||||
return inlineArraySplice(callInfo);
|
||||
|
||||
// Atomic natives.
|
||||
case InlinableNative::AtomicsCompareExchange:
|
||||
@ -667,45 +665,6 @@ IonBuilder::inlineArrayPopShift(CallInfo& callInfo, MArrayPopShift::Mode mode)
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineArraySplice(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 2 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
// Ensure |this|, argument and result are objects.
|
||||
if (getInlineReturnType() != MIRType::Object)
|
||||
return InliningStatus_NotInlined;
|
||||
if (callInfo.thisArg()->type() != MIRType::Object)
|
||||
return InliningStatus_NotInlined;
|
||||
if (callInfo.getArg(0)->type() != MIRType::Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
if (callInfo.getArg(1)->type() != MIRType::Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
// Specialize arr.splice(start, deleteCount) with unused return value and
|
||||
// avoid creating the result array in this case.
|
||||
if (!BytecodeIsPopped(pc)) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineGeneric);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
MArraySplice* ins = MArraySplice::New(alloc(),
|
||||
callInfo.thisArg(),
|
||||
callInfo.getArg(0),
|
||||
callInfo.getArg(1));
|
||||
|
||||
current->add(ins);
|
||||
pushConstant(UndefinedValue());
|
||||
|
||||
MOZ_TRY(resumeAfter(ins));
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineArrayJoin(CallInfo& callInfo)
|
||||
{
|
||||
|
@ -4224,27 +4224,6 @@ class MCallDOMNative : public MCall
|
||||
virtual void computeMovable() override;
|
||||
};
|
||||
|
||||
// arr.splice(start, deleteCount) with unused return value.
|
||||
class MArraySplice
|
||||
: public MTernaryInstruction,
|
||||
public Mix3Policy<ObjectPolicy<0>, IntPolicy<1>, IntPolicy<2> >::Data
|
||||
{
|
||||
private:
|
||||
|
||||
MArraySplice(MDefinition* object, MDefinition* start, MDefinition* deleteCount)
|
||||
: MTernaryInstruction(object, start, deleteCount)
|
||||
{ }
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(ArraySplice)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
NAMED_OPERANDS((0, object), (1, start), (2, deleteCount))
|
||||
|
||||
bool possiblyCalls() const override {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// fun.apply(self, arguments)
|
||||
class MApplyArgs
|
||||
: public MAryInstruction<3>,
|
||||
|
@ -69,7 +69,6 @@ namespace jit {
|
||||
_(Call) \
|
||||
_(ApplyArgs) \
|
||||
_(ApplyArray) \
|
||||
_(ArraySplice) \
|
||||
_(Bail) \
|
||||
_(Unreachable) \
|
||||
_(EncodeSnapshot) \
|
||||
|
@ -323,18 +323,6 @@ StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs, bool* res)
|
||||
template bool StringsEqual<true>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
|
||||
template bool StringsEqual<false>(JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
|
||||
|
||||
bool
|
||||
ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount)
|
||||
{
|
||||
JS::AutoValueArray<4> argv(cx);
|
||||
argv[0].setUndefined();
|
||||
argv[1].setObject(*obj);
|
||||
argv[2].set(Int32Value(start));
|
||||
argv[3].set(Int32Value(deleteCount));
|
||||
|
||||
return js::array_splice_impl(cx, 2, argv.begin(), false);
|
||||
}
|
||||
|
||||
bool
|
||||
ArrayPopDense(JSContext* cx, HandleObject obj, MutableHandleValue rval)
|
||||
{
|
||||
|
@ -767,9 +767,6 @@ InitBaselineFrameForOsr(BaselineFrame* frame, InterpreterFrame* interpFrame,
|
||||
JSObject* CreateDerivedTypedObj(JSContext* cx, HandleObject descr,
|
||||
HandleObject owner, int32_t offset);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
ArraySpliceDense(JSContext* cx, HandleObject obj, uint32_t start, uint32_t deleteCount);
|
||||
|
||||
MOZ_MUST_USE bool
|
||||
Recompile(JSContext* cx);
|
||||
MOZ_MUST_USE bool
|
||||
|
@ -2233,34 +2233,6 @@ class LApplyArrayGeneric : public LCallInstructionHelper<BOX_PIECES, BOX_PIECES
|
||||
}
|
||||
};
|
||||
|
||||
class LArraySplice : public LCallInstructionHelper<0, 3, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(ArraySplice)
|
||||
|
||||
LArraySplice(const LAllocation& object, const LAllocation& start,
|
||||
const LAllocation& deleteCount)
|
||||
{
|
||||
setOperand(0, object);
|
||||
setOperand(1, start);
|
||||
setOperand(2, deleteCount);
|
||||
}
|
||||
|
||||
MArraySplice* mir() const {
|
||||
return mir_->toArraySplice();
|
||||
}
|
||||
|
||||
const LAllocation* getObject() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation* getStart() {
|
||||
return getOperand(1);
|
||||
}
|
||||
const LAllocation* getDeleteCount() {
|
||||
return getOperand(2);
|
||||
}
|
||||
};
|
||||
|
||||
class LGetDynamicName : public LCallInstructionHelper<BOX_PIECES, 2, 3>
|
||||
{
|
||||
public:
|
||||
|
@ -69,7 +69,6 @@
|
||||
_(NewArrayDynamicLength) \
|
||||
_(NewTypedArray) \
|
||||
_(NewTypedArrayDynamicLength) \
|
||||
_(ArraySplice) \
|
||||
_(NewObject) \
|
||||
_(NewTypedObject) \
|
||||
_(NewNamedLambdaObject) \
|
||||
|
@ -2482,13 +2482,6 @@ CanOptimizeForDenseStorage(HandleObject arr, uint32_t startingIndex, uint32_t co
|
||||
startingIndex + count <= GetAnyBoxedOrUnboxedInitializedLength(arr);
|
||||
}
|
||||
|
||||
/* ES 2016 draft Mar 25, 2016 22.1.3.26. */
|
||||
bool
|
||||
js::array_splice(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
return array_splice_impl(cx, argc, vp, true);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ArraySpliceCopy(JSContext* cx, HandleObject arr, HandleObject obj,
|
||||
uint32_t actualStart, uint32_t actualDeleteCount)
|
||||
@ -2518,8 +2511,8 @@ ArraySpliceCopy(JSContext* cx, HandleObject arr, HandleObject obj,
|
||||
return SetLengthProperty(cx, arr, actualDeleteCount);
|
||||
}
|
||||
|
||||
bool
|
||||
js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed)
|
||||
static bool
|
||||
array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed)
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.splice");
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
@ -2763,6 +2756,19 @@ js::array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueI
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ES 2016 draft Mar 25, 2016 22.1.3.26. */
|
||||
bool
|
||||
js::array_splice(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
return array_splice_impl(cx, argc, vp, true);
|
||||
}
|
||||
|
||||
static bool
|
||||
array_splice_noRetVal(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
return array_splice_impl(cx, argc, vp, false);
|
||||
}
|
||||
|
||||
struct SortComparatorIndexes
|
||||
{
|
||||
bool operator()(uint32_t a, uint32_t b, bool* lessOrEqualp) {
|
||||
@ -3177,6 +3183,15 @@ array_of(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
const JSJitInfo js::array_splice_info = {
|
||||
{ (JSJitGetterOp)array_splice_noRetVal },
|
||||
{ 0 }, /* unused */
|
||||
{ 0 }, /* unused */
|
||||
JSJitInfo::IgnoresReturnValueNative,
|
||||
JSJitInfo::AliasEverything,
|
||||
JSVAL_TYPE_UNDEFINED,
|
||||
};
|
||||
|
||||
static const JSFunctionSpec array_methods[] = {
|
||||
#if JS_HAS_TOSOURCE
|
||||
JS_FN(js_toSource_str, array_toSource, 0,0),
|
||||
@ -3192,7 +3207,7 @@ static const JSFunctionSpec array_methods[] = {
|
||||
JS_INLINABLE_FN("pop", array_pop, 0,0, ArrayPop),
|
||||
JS_INLINABLE_FN("shift", array_shift, 0,0, ArrayShift),
|
||||
JS_FN("unshift", array_unshift, 1,0),
|
||||
JS_INLINABLE_FN("splice", array_splice, 2,0, ArraySplice),
|
||||
JS_FNINFO("splice", array_splice, &array_splice_info, 2,0),
|
||||
|
||||
/* Pythonic sequence methods. */
|
||||
JS_SELF_HOSTED_FN("concat", "ArrayConcat", 1,0),
|
||||
|
@ -165,9 +165,6 @@ array_push(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
extern bool
|
||||
array_pop(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
|
||||
extern bool
|
||||
array_splice_impl(JSContext* cx, unsigned argc, js::Value* vp, bool pop);
|
||||
|
||||
extern bool
|
||||
array_join(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
|
||||
@ -192,6 +189,8 @@ array_reverse(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
extern bool
|
||||
array_splice(JSContext* cx, unsigned argc, js::Value* vp);
|
||||
|
||||
extern const JSJitInfo array_splice_info;
|
||||
|
||||
/*
|
||||
* Append the given (non-hole) value to the end of an array. The array must be
|
||||
* a newborn array -- that is, one which has not been exposed to script for
|
||||
|
@ -2306,7 +2306,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
JS_INLINABLE_FN("std_Array_slice", array_slice, 2,0, ArraySlice),
|
||||
JS_FN("std_Array_sort", array_sort, 1,0),
|
||||
JS_FN("std_Array_reverse", array_reverse, 0,0),
|
||||
JS_INLINABLE_FN("std_Array_splice", array_splice, 2,0, ArraySplice),
|
||||
JS_FNINFO("std_Array_splice", array_splice, &array_splice_info, 2,0),
|
||||
|
||||
JS_FN("std_Date_now", date_now, 0,0),
|
||||
JS_FN("std_Date_valueOf", date_valueOf, 0,0),
|
||||
|
Loading…
x
Reference in New Issue
Block a user