diff options
Diffstat (limited to 'js/src/jit')
-rw-r--r-- | js/src/jit/BaselineBailouts.cpp | 56 | ||||
-rw-r--r-- | js/src/jit/CodeGenerator.cpp | 26 | ||||
-rw-r--r-- | js/src/jit/CodeGenerator.h | 1 | ||||
-rw-r--r-- | js/src/jit/InlinableNatives.h | 10 | ||||
-rw-r--r-- | js/src/jit/IonBuilder.h | 1 | ||||
-rw-r--r-- | js/src/jit/JitFrameIterator.h | 4 | ||||
-rw-r--r-- | js/src/jit/JitFrames.cpp | 4 | ||||
-rw-r--r-- | js/src/jit/Lowering.cpp | 10 | ||||
-rw-r--r-- | js/src/jit/Lowering.h | 1 | ||||
-rw-r--r-- | js/src/jit/MCallOptimize.cpp | 51 | ||||
-rw-r--r-- | js/src/jit/MIR.h | 42 | ||||
-rw-r--r-- | js/src/jit/MOpcodes.h | 1 | ||||
-rw-r--r-- | js/src/jit/shared/LIR-shared.h | 23 | ||||
-rw-r--r-- | js/src/jit/shared/LOpcodes-shared.h | 1 |
14 files changed, 176 insertions, 55 deletions
diff --git a/js/src/jit/BaselineBailouts.cpp b/js/src/jit/BaselineBailouts.cpp index 3ab722b3d..ad2757ae1 100644 --- a/js/src/jit/BaselineBailouts.cpp +++ b/js/src/jit/BaselineBailouts.cpp @@ -419,41 +419,6 @@ struct BaselineStackBuilder } }; -// Ensure that all value locations are readable from the SnapshotIterator. -// Remove RInstructionResults from the JitActivation if the frame got recovered -// ahead of the bailout. -class SnapshotIteratorForBailout : public SnapshotIterator -{ - JitActivation* activation_; - JitFrameIterator& iter_; - - public: - SnapshotIteratorForBailout(JitActivation* activation, JitFrameIterator& iter) - : SnapshotIterator(iter, activation->bailoutData()->machineState()), - activation_(activation), - iter_(iter) - { - MOZ_ASSERT(iter.isBailoutJS()); - } - - ~SnapshotIteratorForBailout() { - // The bailout is complete, we no longer need the recover instruction - // results. - activation_->removeIonFrameRecovery(fp_); - } - - // Take previously computed result out of the activation, or compute the - // results of all recover instructions contained in the snapshot. - MOZ_MUST_USE bool init(JSContext* cx) { - - // Under a bailout, there is no need to invalidate the frame after - // evaluating the recover instruction, as the invalidation is only - // needed to cause of the frame which has been introspected. - MaybeReadFallback recoverBailout(cx, activation_, &iter_, MaybeReadFallback::Fallback_DoNothing); - return initInstructionResults(recoverBailout); - } -}; - #ifdef DEBUG static inline bool IsInlinableFallback(ICFallbackStub* icEntry) @@ -1476,6 +1441,7 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter { MOZ_ASSERT(bailoutInfo != nullptr); MOZ_ASSERT(*bailoutInfo == nullptr); + MOZ_ASSERT(iter.isBailoutJS()); TraceLoggerThread* logger = TraceLoggerForMainThread(cx->runtime()); TraceLogStopEvent(logger, TraceLogger_IonMonkey); @@ -1488,6 +1454,12 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter activation->removeRematerializedFramesFromDebugger(cx, iter.fp()); }); + // Always remove the RInstructionResults from the JitActivation, even in + // case of failures as the stack frame is going away after the bailout. + auto removeIonFrameRecovery = mozilla::MakeScopeExit([&] { + activation->removeIonFrameRecovery(iter.jsFrame()); + }); + // The caller of the top frame must be one of the following: // IonJS - Ion calling into Ion. // BaselineStub - Baseline calling into Ion. @@ -1561,9 +1533,19 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter } JitSpew(JitSpew_BaselineBailouts, " Incoming frame ptr = %p", builder.startFrame()); - SnapshotIteratorForBailout snapIter(activation, iter); - if (!snapIter.init(cx)) + // Under a bailout, there is no need to invalidate the frame after + // evaluating the recover instruction, as the invalidation is only needed in + // cases where the frame is introspected ahead of the bailout. + MaybeReadFallback recoverBailout(cx, activation, &iter, MaybeReadFallback::Fallback_DoNothing); + + // Ensure that all value locations are readable from the SnapshotIterator. + // Get the RInstructionResults from the JitActivation if the frame got + // recovered ahead of the bailout. + SnapshotIterator snapIter(iter, activation->bailoutData()->machineState()); + if (!snapIter.initInstructionResults(recoverBailout)) { + ReportOutOfMemory(cx); return BAILOUT_RETURN_FATAL_ERROR; + } #ifdef TRACK_SNAPSHOTS snapIter.spewBailingFrom(); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 7b2f8214b..16d026092 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -11529,6 +11529,32 @@ CodeGenerator::visitHasClass(LHasClass* ins) } void +CodeGenerator::visitGuardToClass(LGuardToClass* ins) +{ + Register lhs = ToRegister(ins->lhs()); + Register output = ToRegister(ins->output()); + Register temp = ToRegister(ins->temp()); + + Label notEqual; + + masm.branchTestObjClass(Assembler::NotEqual, lhs, temp, ins->mir()->getClass(), ¬Equal); + masm.mov(lhs, output); + + if (ins->mir()->type() == MIRType::Object) { + // Can't return null-return here, so bail + bailoutFrom(¬Equal, ins->snapshot()); + } else { + Label done; + masm.jump(&done); + + masm.bind(¬Equal); + masm.mov(ImmPtr(0), output); + + masm.bind(&done); + } +} + +void CodeGenerator::visitWasmParameter(LWasmParameter* lir) { } diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index d3126651b..b226f6cc9 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -377,6 +377,7 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitIsObject(LIsObject* lir); void visitIsObjectAndBranch(LIsObjectAndBranch* lir); void visitHasClass(LHasClass* lir); + void visitGuardToClass(LGuardToClass* lir); void visitWasmParameter(LWasmParameter* lir); void visitWasmParameterI64(LWasmParameterI64* lir); void visitWasmReturn(LWasmReturn* ret); diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index 89c2ff0a4..18535389a 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -117,14 +117,16 @@ _(IntrinsicDefineDataProperty) \ _(IntrinsicObjectHasPrototype) \ \ - _(IntrinsicIsArrayIterator) \ - _(IntrinsicIsMapIterator) \ - _(IntrinsicIsSetIterator) \ - _(IntrinsicIsStringIterator) \ + _(IntrinsicGuardToArrayIterator) \ + _(IntrinsicGuardToMapIterator) \ + _(IntrinsicGuardToSetIterator) \ _(IntrinsicIsListIterator) \ + _(IntrinsicGuardToStringIterator) \ \ + _(IntrinsicGuardToMapObject) \ _(IntrinsicGetNextMapEntryForIterator) \ \ + _(IntrinsicGuardToSetObject) \ _(IntrinsicGetNextSetEntryForIterator) \ \ _(IntrinsicArrayBufferByteLength) \ diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 35ad120f7..f24ef30c8 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -969,6 +969,7 @@ class IonBuilder const Class* clasp2 = nullptr, const Class* clasp3 = nullptr, const Class* clasp4 = nullptr); + InliningStatus inlineGuardToClass(CallInfo& callInfo, const Class* clasp); InliningStatus inlineIsConstructing(CallInfo& callInfo); InliningStatus inlineSubstringKernel(CallInfo& callInfo); InliningStatus inlineObjectHasPrototype(CallInfo& callInfo); diff --git a/js/src/jit/JitFrameIterator.h b/js/src/jit/JitFrameIterator.h index ba5efef6a..76d04d092 100644 --- a/js/src/jit/JitFrameIterator.h +++ b/js/src/jit/JitFrameIterator.h @@ -322,9 +322,7 @@ class RInstructionResults MOZ_MUST_USE bool init(JSContext* cx, uint32_t numResults); bool isInitialized() const; -#ifdef DEBUG size_t length() const; -#endif JitFrameLayout* frame() const; @@ -511,13 +509,13 @@ class SnapshotIterator return recover_.moreInstructions(); } - protected: // Register a vector used for storing the results of the evaluation of // recover instructions. This vector should be registered before the // beginning of the iteration. This function is in charge of allocating // enough space for all instructions results, and return false iff it fails. MOZ_MUST_USE bool initInstructionResults(MaybeReadFallback& fallback); + protected: // This function is used internally for computing the result of the recover // instructions. MOZ_MUST_USE bool computeInstructionResults(JSContext* cx, RInstructionResults* results) const; diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index f11f17225..019be46dd 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -1688,13 +1688,11 @@ RInstructionResults::isInitialized() const return initialized_; } -#ifdef DEBUG size_t RInstructionResults::length() const { return results_->length(); } -#endif JitFrameLayout* RInstructionResults::frame() const @@ -2150,7 +2148,7 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback& fallback) } MOZ_ASSERT(results->isInitialized()); - MOZ_ASSERT(results->length() == recover_.numInstructions() - 1); + MOZ_RELEASE_ASSERT(results->length() == recover_.numInstructions() - 1); instructionResults_ = results; return true; } diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 730697163..709de9987 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -4171,6 +4171,16 @@ LIRGenerator::visitHasClass(MHasClass* ins) } void +LIRGenerator::visitGuardToClass(MGuardToClass* ins) +{ + MOZ_ASSERT(ins->object()->type() == MIRType::Object); + MOZ_ASSERT(ins->type() == MIRType::ObjectOrNull|| ins->type() == MIRType::Object); + LGuardToClass* lir = new(alloc()) LGuardToClass(useRegister(ins->object()), temp()); + assignSnapshot(lir, Bailout_TypeBarrierO); + define(lir, ins); +} + +void LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins) { MOZ_ASSERT(ins->base()->type() == MIRType::Int32); diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h index b2805cb7a..9b4095aec 100644 --- a/js/src/jit/Lowering.h +++ b/js/src/jit/Lowering.h @@ -289,6 +289,7 @@ class LIRGenerator : public LIRGeneratorSpecific void visitIsConstructor(MIsConstructor* ins); void visitIsObject(MIsObject* ins); void visitHasClass(MHasClass* ins); + void visitGuardToClass(MGuardToClass* ins); void visitWasmAddOffset(MWasmAddOffset* ins); void visitWasmBoundsCheck(MWasmBoundsCheck* ins); void visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 202aef497..01755094a 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -280,14 +280,14 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlineIsConstructing(callInfo); case InlinableNative::IntrinsicSubstringKernel: return inlineSubstringKernel(callInfo); - case InlinableNative::IntrinsicIsArrayIterator: - return inlineHasClass(callInfo, &ArrayIteratorObject::class_); - case InlinableNative::IntrinsicIsMapIterator: - return inlineHasClass(callInfo, &MapIteratorObject::class_); - case InlinableNative::IntrinsicIsSetIterator: - return inlineHasClass(callInfo, &SetIteratorObject::class_); - case InlinableNative::IntrinsicIsStringIterator: - return inlineHasClass(callInfo, &StringIteratorObject::class_); + case InlinableNative::IntrinsicGuardToArrayIterator: + return inlineGuardToClass(callInfo, &ArrayIteratorObject::class_); + case InlinableNative::IntrinsicGuardToMapIterator: + return inlineGuardToClass(callInfo, &MapIteratorObject::class_); + case InlinableNative::IntrinsicGuardToSetIterator: + return inlineGuardToClass(callInfo, &SetIteratorObject::class_); + case InlinableNative::IntrinsicGuardToStringIterator: + return inlineGuardToClass(callInfo, &StringIteratorObject::class_); case InlinableNative::IntrinsicIsListIterator: return inlineHasClass(callInfo, &ListIteratorObject::class_); case InlinableNative::IntrinsicDefineDataProperty: @@ -296,10 +296,14 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) return inlineObjectHasPrototype(callInfo); // Map intrinsics. + case InlinableNative::IntrinsicGuardToMapObject: + return inlineGuardToClass(callInfo, &MapObject::class_); case InlinableNative::IntrinsicGetNextMapEntryForIterator: return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Map); // Set intrinsics. + case InlinableNative::IntrinsicGuardToSetObject: + return inlineGuardToClass(callInfo, &SetObject::class_); case InlinableNative::IntrinsicGetNextSetEntryForIterator: return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Set); @@ -2220,6 +2224,37 @@ IonBuilder::inlineHasClass(CallInfo& callInfo, } IonBuilder::InliningStatus +IonBuilder::inlineGuardToClass(CallInfo& callInfo, const Class* clasp) +{ + MOZ_ASSERT(!callInfo.constructing()); + MOZ_ASSERT(callInfo.argc() == 1); + + if (callInfo.getArg(0)->type() != MIRType::Object) + return InliningStatus_NotInlined; + + if (getInlineReturnType() != MIRType::ObjectOrNull && + getInlineReturnType() != MIRType::Object) + { + return InliningStatus_NotInlined; + } + + TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet(); + const Class* knownClass = types ? types->getKnownClass(constraints()) : nullptr; + + if (knownClass && knownClass == clasp) { + current->push(callInfo.getArg(0)); + } else { + MGuardToClass* guardToClass = MGuardToClass::New(alloc(), callInfo.getArg(0), + clasp, getInlineReturnType()); + current->add(guardToClass); + current->push(guardToClass); + } + + callInfo.setImplicitlyUsedUnchecked(); + return InliningStatus_Inlined; +} + +IonBuilder::InliningStatus IonBuilder::inlineGetNextEntryForIterator(CallInfo& callInfo, MGetNextEntryForIterator::Mode mode) { if (callInfo.argc() != 2 || callInfo.constructing()) { diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index 2de91e2df..6ec05af76 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -13192,6 +13192,48 @@ class MHasClass } }; +class MGuardToClass + : public MUnaryInstruction, + public SingleObjectPolicy::Data +{ + const Class* class_; + + MGuardToClass(MDefinition* object, const Class* clasp, MIRType resultType) + : MUnaryInstruction(object) + , class_(clasp) + { + MOZ_ASSERT(object->type() == MIRType::Object || + (object->type() == MIRType::Value && object->mightBeType(MIRType::Object))); + MOZ_ASSERT(resultType == MIRType::Object || resultType == MIRType::ObjectOrNull); + setResultType(resultType); + setMovable(); + if (resultType == MIRType::Object) { + // We will bail out if the class type is incorrect, + // so we need to ensure we don't eliminate this instruction + setGuard(); + } + } + + public: + INSTRUCTION_HEADER(GuardToClass) + TRIVIAL_NEW_WRAPPERS + NAMED_OPERANDS((0, object)) + + const Class* getClass() const { + return class_; + } + AliasSet getAliasSet() const override { + return AliasSet::None(); + } + bool congruentTo(const MDefinition* ins) const override { + if (!ins->isGuardToClass()) + return false; + if (getClass() != ins->toGuardToClass()->getClass()) + return false; + return congruentIfOperandsEqual(ins); + } +}; + class MCheckReturn : public MBinaryInstruction, public BoxInputsPolicy::Data diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h index bb2ab8190..fddc1e637 100644 --- a/js/src/jit/MOpcodes.h +++ b/js/src/jit/MOpcodes.h @@ -272,6 +272,7 @@ namespace jit { _(IsCallable) \ _(IsObject) \ _(HasClass) \ + _(GuardToClass) \ _(CopySign) \ _(Rotate) \ _(NewDerivedTypedObject) \ diff --git a/js/src/jit/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h index 9dcb527c5..f4adcc63c 100644 --- a/js/src/jit/shared/LIR-shared.h +++ b/js/src/jit/shared/LIR-shared.h @@ -7867,6 +7867,29 @@ class LHasClass : public LInstructionHelper<1, 1, 0> } }; +class LGuardToClass : public LInstructionHelper<1, 1, 1> +{ + public: + LIR_HEADER(GuardToClass); + explicit LGuardToClass(const LAllocation& lhs, const LDefinition& temp) + { + setOperand(0, lhs); + setTemp(0, temp); + } + + const LAllocation* lhs() { + return getOperand(0); + } + + const LDefinition* temp() { + return getTemp(0); + } + + MGuardToClass* mir() const { + return mir_->toGuardToClass(); + } +}; + template<size_t Defs, size_t Ops> class LWasmSelectBase : public LInstructionHelper<Defs, Ops, 0> { diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h index 3eea1b449..fe2ab5ea3 100644 --- a/js/src/jit/shared/LOpcodes-shared.h +++ b/js/src/jit/shared/LOpcodes-shared.h @@ -386,6 +386,7 @@ _(IsObject) \ _(IsObjectAndBranch) \ _(HasClass) \ + _(GuardToClass) \ _(RecompileCheck) \ _(MemoryBarrier) \ _(AssertRangeI) \ |