From 32cff5d448b492afa7124e5fab5e126fee4e4dce Mon Sep 17 00:00:00 2001 From: Tooru Fujisawa Date: Sun, 19 Mar 2017 14:16:36 +0900 Subject: [PATCH] Bug 1344477 - Part 2: Optimize Array.prototype.splice with JSOP_NORVCALL. r=jandem --- js/src/jit/CodeGenerator.cpp | 13 --------- js/src/jit/CodeGenerator.h | 1 - js/src/jit/InlinableNatives.h | 1 - js/src/jit/IonBuilder.h | 1 - js/src/jit/Lowering.cpp | 10 ------- js/src/jit/Lowering.h | 1 - js/src/jit/MCallOptimize.cpp | 41 ----------------------------- js/src/jit/MIR.h | 21 --------------- js/src/jit/MOpcodes.h | 1 - js/src/jit/VMFunctions.cpp | 12 --------- js/src/jit/VMFunctions.h | 3 --- js/src/jit/shared/LIR-shared.h | 28 -------------------- js/src/jit/shared/LOpcodes-shared.h | 1 - js/src/jsarray.cpp | 35 +++++++++++++++++------- js/src/jsarray.h | 5 ++-- js/src/vm/SelfHosting.cpp | 2 +- 16 files changed, 28 insertions(+), 148 deletions(-) diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 06f1ef2d2122..461e0d46e653 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -4666,19 +4666,6 @@ CodeGenerator::visitApplyArrayGeneric(LApplyArrayGeneric* apply) emitApplyGeneric(apply); } -typedef bool (*ArraySpliceDenseFn)(JSContext*, HandleObject, uint32_t, uint32_t); -static const VMFunction ArraySpliceDenseInfo = - FunctionInfo(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) { diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index cc80f427c06d..6fe5652c0ced 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -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); diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index fc01535b1b0c..082bd6d009ec 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -15,7 +15,6 @@ _(ArrayShift) \ _(ArrayPush) \ _(ArraySlice) \ - _(ArraySplice) \ \ _(AtomicsCompareExchange) \ _(AtomicsExchange) \ diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index a1ee125d74e9..d85d2b0fd431 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -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); diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 30f0321dd170..f93603c6ab84 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -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) { diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index c24fbcae9a14..d0b93e142ce2 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -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); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 2c8af9f4cab7..eafd0e866155 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -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) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index bdddef30503f..52abc69f06ad 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -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, 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>, diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index ff294a9ebba1..4d7662b67019 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -69,7 +69,6 @@ namespace jit { _(Call) \ _(ApplyArgs) \ _(ApplyArray) \ - _(ArraySplice) \ _(Bail) \ _(Unreachable) \ _(EncodeSnapshot) \ diff --git a/js/src/jit/VMFunctions.cpp b/js/src/jit/VMFunctions.cpp index e800c8a5beb7..b9531fa13a9a 100644 --- a/js/src/jit/VMFunctions.cpp +++ b/js/src/jit/VMFunctions.cpp @@ -323,18 +323,6 @@ StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs, bool* res) template bool StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs, bool* res); template bool StringsEqual(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) { diff --git a/js/src/jit/VMFunctions.h b/js/src/jit/VMFunctions.h index 7b7bd6b10321..a5fad9054fdb 100644 --- a/js/src/jit/VMFunctions.h +++ b/js/src/jit/VMFunctions.h @@ -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 diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index b7395258e951..0c632201ec06 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -2233,34 +2233,6 @@ class LApplyArrayGeneric : public LCallInstructionHelper -{ - 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 { public: diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index 2cfdbb364131..ddf68490f8d4 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -69,7 +69,6 @@ _(NewArrayDynamicLength) \ _(NewTypedArray) \ _(NewTypedArrayDynamicLength) \ - _(ArraySplice) \ _(NewObject) \ _(NewTypedObject) \ _(NewNamedLambdaObject) \ diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index 040e0d832188..8facc42c68aa 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -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), diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 13f2b70f728f..fd35ee524b55 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -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 diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 261061b28f97..0d05e5784190 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -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),