Loading js/src/jit/CodeGenerator.cpp +23 −0 Changes for js/src/jit/CodeGenerator.cpp: 23 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -6003,6 +6003,19 @@ static void LoadDOMPrivate(MacroAssembler& masm, Register obj, Register priv, } } void CodeGenerator::maybeEmitSetInPureCall(MInstruction* mir, bool value, Register scratch) { AliasSet aliasSet = mir->getAliasSet(); if (aliasSet.isStore() && (aliasSet.flags() & AliasSet::ObjectFields) != 0) { // If the alias set already indicates that this can reallocate slots, the // flag is unnecessary. return; } const void* addr = gen->jitRuntime()->addressOfInPureCall(); masm.move32(Imm32(value), scratch); masm.store32(scratch, AbsoluteAddress(addr)); } void CodeGenerator::visitCallDOMNative(LCallDOMNative* call) { WrappedFunction* target = call->getSingleTarget(); MOZ_ASSERT(target); Loading Loading @@ -6090,6 +6103,8 @@ void CodeGenerator::visitCallDOMNative(LCallDOMNative* call) { markSafepointAt(safepointOffset, call); maybeEmitSetInPureCall(call->mir(), true, /*scratch =*/argJSContext); // Construct and execute call. masm.setupAlignedABICall(); masm.loadJSContext(argJSContext); Loading @@ -6102,6 +6117,9 @@ void CodeGenerator::visitCallDOMNative(LCallDOMNative* call) { ABIType::General, CheckUnsafeCallWithABI::DontCheckHasExitFrame); Register notReturnReg = argJSContext == ReturnReg ? argObj : argJSContext; maybeEmitSetInPureCall(call->mir(), false, /*scratch =*/notReturnReg); if (target->jitInfo()->isInfallible) { masm.loadValue(Address(masm.getStackPointer(), IonDOMMethodExitFrameLayout::offsetOfResult()), Loading Loading @@ -19188,6 +19206,8 @@ void CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins) { markSafepointAt(safepointOffset, ins); maybeEmitSetInPureCall(ins->mir(), true, /*scratch =*/JSContextReg); masm.setupAlignedABICall(); masm.loadJSContext(JSContextReg); masm.passABIArg(JSContextReg); Loading @@ -19199,6 +19219,9 @@ void CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins) { ABIType::General, CheckUnsafeCallWithABI::DontCheckHasExitFrame); Register notReturnReg = JSContextReg == ReturnReg ? ObjectReg : JSContextReg; maybeEmitSetInPureCall(ins->mir(), false, /*scratch =*/notReturnReg); if (ins->mir()->isInfallible()) { masm.loadValue(Address(masm.getStackPointer(), IonDOMExitFrameLayout::offsetOfResult()), js/src/jit/CodeGenerator.h +1 −0 Changes for js/src/jit/CodeGenerator.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -402,6 +402,7 @@ class CodeGenerator final : public CodeGeneratorSpecific { #define LIR_OP(op) void visit##op(L##op* ins); LIR_OPCODE_LIST(LIR_OP) #undef LIR_OP void maybeEmitSetInPureCall(MInstruction* mir, bool value, Register scratch); // In debug mode, we need to validate that we've not made a mistake with the // fuse. Loading js/src/jit/Ion.cpp +29 −0 Changes for js/src/jit/Ion.cpp: 29 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ #include "gc/GC-inl.h" #include "gc/StableCellHasher-inl.h" #include "jit/InlineScriptTree-inl.h" #include "jit/JSJitFrameIter-inl.h" #include "jit/MacroAssembler-inl.h" #include "jit/SafepointIndex-inl.h" #include "vm/GeckoProfiler-inl.h" Loading Loading @@ -450,6 +451,34 @@ void JitRuntime::TraceWeakJitcodeGlobalTable(JSRuntime* rt, JSTracer* trc) { } } void JitRuntime::handleGrowSlotsForPureCall(JSContext* cx) { MOZ_ASSERT(inPureCall()); // We only set the inPureCall flag for calls in Ion code with alias // sets that claim not to have arbitrary side-effects. Therefore, we // should not have re-entered JIT code, and the call that set the // flag should be the innermost frame (aside from the exit frame). MOZ_RELEASE_ASSERT(cx->activation()->isJit()); JitActivation* activation = cx->activation()->asJit(); MOZ_RELEASE_ASSERT(activation->hasExitFP()); JSJitFrameIter frame(activation); // We currently only set this flag for DOM calls. MOZ_RELEASE_ASSERT(frame.isExitFrameLayout<IonDOMExitFrameLayout>()); ++frame; MOZ_RELEASE_ASSERT(frame.isIonJS()); // If we've already invalidated, we've cleared the IonScript // pointer, so we can't invalidate again. if (frame.checkInvalidation()) { return; } JitSpew(JitSpew_IonInvalidate, "Invalidating frame: slots reallocated during pure call"); Invalidate(cx, frame.script()); } bool JitZone::addInlinedCompilation(const RecompileInfo& info, JSScript* inlined) { MOZ_ASSERT(inlined != info.script()); Loading js/src/jit/JitRuntime.h +10 −0 Changes for js/src/jit/JitRuntime.h: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -247,6 +247,11 @@ class JitRuntime { MainThreadData<uint32_t> disallowArbitraryCode_{false}; #endif // Flag that can be set from JIT code to indicate that we're calling // a function whose alias set does not include stores to ObjectFields. // See handleGrowSlotsForPureCall. MainThreadData<uint32_t> inPureCall_{false}; bool generateTrampolines(JSContext* cx); bool generateBaselineICFallbackCode(JSContext* cx); Loading Loading @@ -347,6 +352,9 @@ class JitRuntime { } #endif bool inPureCall() const { return inPureCall_; } const void* addressOfInPureCall() const { return &inPureCall_.refNoCheck(); } uint8_t* allocateIonOsrTempData(size_t size); void freeIonOsrTempData(); Loading Loading @@ -512,6 +520,8 @@ class JitRuntime { void ionLazyLinkListRemove(JSRuntime* rt, js::jit::IonCompileTask* task); void ionLazyLinkListAdd(JSRuntime* rt, js::jit::IonCompileTask* task); void handleGrowSlotsForPureCall(JSContext* cx); }; } // namespace jit Loading js/src/vm/Interpreter.cpp +2 −0 Changes for js/src/vm/Interpreter.cpp: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -416,6 +416,8 @@ bool js::RunScript(JSContext* cx, RunState& state) { MOZ_ASSERT_IF(cx->runtime()->hasJitRuntime(), !cx->runtime()->jitRuntime()->disallowArbitraryCode()); MOZ_ASSERT_IF(cx->runtime()->hasJitRuntime(), !cx->runtime()->jitRuntime()->inPureCall()); // Since any script can conceivably GC, make sure it's safe to do so. cx->verifyIsSafeToGC(); Loading Loading
js/src/jit/CodeGenerator.cpp +23 −0 Changes for js/src/jit/CodeGenerator.cpp: 23 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -6003,6 +6003,19 @@ static void LoadDOMPrivate(MacroAssembler& masm, Register obj, Register priv, } } void CodeGenerator::maybeEmitSetInPureCall(MInstruction* mir, bool value, Register scratch) { AliasSet aliasSet = mir->getAliasSet(); if (aliasSet.isStore() && (aliasSet.flags() & AliasSet::ObjectFields) != 0) { // If the alias set already indicates that this can reallocate slots, the // flag is unnecessary. return; } const void* addr = gen->jitRuntime()->addressOfInPureCall(); masm.move32(Imm32(value), scratch); masm.store32(scratch, AbsoluteAddress(addr)); } void CodeGenerator::visitCallDOMNative(LCallDOMNative* call) { WrappedFunction* target = call->getSingleTarget(); MOZ_ASSERT(target); Loading Loading @@ -6090,6 +6103,8 @@ void CodeGenerator::visitCallDOMNative(LCallDOMNative* call) { markSafepointAt(safepointOffset, call); maybeEmitSetInPureCall(call->mir(), true, /*scratch =*/argJSContext); // Construct and execute call. masm.setupAlignedABICall(); masm.loadJSContext(argJSContext); Loading @@ -6102,6 +6117,9 @@ void CodeGenerator::visitCallDOMNative(LCallDOMNative* call) { ABIType::General, CheckUnsafeCallWithABI::DontCheckHasExitFrame); Register notReturnReg = argJSContext == ReturnReg ? argObj : argJSContext; maybeEmitSetInPureCall(call->mir(), false, /*scratch =*/notReturnReg); if (target->jitInfo()->isInfallible) { masm.loadValue(Address(masm.getStackPointer(), IonDOMMethodExitFrameLayout::offsetOfResult()), Loading Loading @@ -19188,6 +19206,8 @@ void CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins) { markSafepointAt(safepointOffset, ins); maybeEmitSetInPureCall(ins->mir(), true, /*scratch =*/JSContextReg); masm.setupAlignedABICall(); masm.loadJSContext(JSContextReg); masm.passABIArg(JSContextReg); Loading @@ -19199,6 +19219,9 @@ void CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins) { ABIType::General, CheckUnsafeCallWithABI::DontCheckHasExitFrame); Register notReturnReg = JSContextReg == ReturnReg ? ObjectReg : JSContextReg; maybeEmitSetInPureCall(ins->mir(), false, /*scratch =*/notReturnReg); if (ins->mir()->isInfallible()) { masm.loadValue(Address(masm.getStackPointer(), IonDOMExitFrameLayout::offsetOfResult()),
js/src/jit/CodeGenerator.h +1 −0 Changes for js/src/jit/CodeGenerator.h: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -402,6 +402,7 @@ class CodeGenerator final : public CodeGeneratorSpecific { #define LIR_OP(op) void visit##op(L##op* ins); LIR_OPCODE_LIST(LIR_OP) #undef LIR_OP void maybeEmitSetInPureCall(MInstruction* mir, bool value, Register scratch); // In debug mode, we need to validate that we've not made a mistake with the // fuse. Loading
js/src/jit/Ion.cpp +29 −0 Changes for js/src/jit/Ion.cpp: 29 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ #include "gc/GC-inl.h" #include "gc/StableCellHasher-inl.h" #include "jit/InlineScriptTree-inl.h" #include "jit/JSJitFrameIter-inl.h" #include "jit/MacroAssembler-inl.h" #include "jit/SafepointIndex-inl.h" #include "vm/GeckoProfiler-inl.h" Loading Loading @@ -450,6 +451,34 @@ void JitRuntime::TraceWeakJitcodeGlobalTable(JSRuntime* rt, JSTracer* trc) { } } void JitRuntime::handleGrowSlotsForPureCall(JSContext* cx) { MOZ_ASSERT(inPureCall()); // We only set the inPureCall flag for calls in Ion code with alias // sets that claim not to have arbitrary side-effects. Therefore, we // should not have re-entered JIT code, and the call that set the // flag should be the innermost frame (aside from the exit frame). MOZ_RELEASE_ASSERT(cx->activation()->isJit()); JitActivation* activation = cx->activation()->asJit(); MOZ_RELEASE_ASSERT(activation->hasExitFP()); JSJitFrameIter frame(activation); // We currently only set this flag for DOM calls. MOZ_RELEASE_ASSERT(frame.isExitFrameLayout<IonDOMExitFrameLayout>()); ++frame; MOZ_RELEASE_ASSERT(frame.isIonJS()); // If we've already invalidated, we've cleared the IonScript // pointer, so we can't invalidate again. if (frame.checkInvalidation()) { return; } JitSpew(JitSpew_IonInvalidate, "Invalidating frame: slots reallocated during pure call"); Invalidate(cx, frame.script()); } bool JitZone::addInlinedCompilation(const RecompileInfo& info, JSScript* inlined) { MOZ_ASSERT(inlined != info.script()); Loading
js/src/jit/JitRuntime.h +10 −0 Changes for js/src/jit/JitRuntime.h: 10 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -247,6 +247,11 @@ class JitRuntime { MainThreadData<uint32_t> disallowArbitraryCode_{false}; #endif // Flag that can be set from JIT code to indicate that we're calling // a function whose alias set does not include stores to ObjectFields. // See handleGrowSlotsForPureCall. MainThreadData<uint32_t> inPureCall_{false}; bool generateTrampolines(JSContext* cx); bool generateBaselineICFallbackCode(JSContext* cx); Loading Loading @@ -347,6 +352,9 @@ class JitRuntime { } #endif bool inPureCall() const { return inPureCall_; } const void* addressOfInPureCall() const { return &inPureCall_.refNoCheck(); } uint8_t* allocateIonOsrTempData(size_t size); void freeIonOsrTempData(); Loading Loading @@ -512,6 +520,8 @@ class JitRuntime { void ionLazyLinkListRemove(JSRuntime* rt, js::jit::IonCompileTask* task); void ionLazyLinkListAdd(JSRuntime* rt, js::jit::IonCompileTask* task); void handleGrowSlotsForPureCall(JSContext* cx); }; } // namespace jit Loading
js/src/vm/Interpreter.cpp +2 −0 Changes for js/src/vm/Interpreter.cpp: 2 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -416,6 +416,8 @@ bool js::RunScript(JSContext* cx, RunState& state) { MOZ_ASSERT_IF(cx->runtime()->hasJitRuntime(), !cx->runtime()->jitRuntime()->disallowArbitraryCode()); MOZ_ASSERT_IF(cx->runtime()->hasJitRuntime(), !cx->runtime()->jitRuntime()->inPureCall()); // Since any script can conceivably GC, make sure it's safe to do so. cx->verifyIsSafeToGC(); Loading