Verified Commit 1a2b7de5 authored by Iain Ireland's avatar Iain Ireland Committed by ma1
Browse files

Bug 2074632: Invalidate Ion when a pure DOM call reallocates the global's slots a=diannaS

parent dfef8b36
Loading
Loading
Loading
Loading
+23 −0
Changes for js/src/jit/CodeGenerator.cpp: 23 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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);
@@ -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);
@@ -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()),
@@ -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);
@@ -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()),
+1 −0
Changes for js/src/jit/CodeGenerator.h: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -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.
+29 −0
Changes for js/src/jit/Ion.cpp: 29 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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"
@@ -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());
+10 −0
Changes for js/src/jit/JitRuntime.h: 10 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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);

@@ -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();

@@ -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
+2 −0
Changes for js/src/vm/Interpreter.cpp: 2 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -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