summaryrefslogtreecommitdiffstats
path: root/js/src/vm/InvalidatingFuse.cpp
blob: cae8875a19327888e8b6a7b37ea06850fcbf807b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "vm/InvalidatingFuse.h"

#include "gc/PublicIterators.h"
#include "jit/Invalidation.h"
#include "jit/JitSpewer.h"
#include "vm/JSContext.h"
#include "vm/JSScript.h"

#include "gc/StableCellHasher-inl.h"
#include "vm/JSScript-inl.h"

js::DependentScriptSet::DependentScriptSet(JSContext* cx,
                                           InvalidatingFuse* fuse)
    : associatedFuse(fuse), weakScripts(cx->runtime()) {}

bool js::InvalidatingRuntimeFuse::addFuseDependency(JSContext* cx,
                                                    Handle<JSScript*> script) {
  auto* zone = script->zone();
  DependentScriptSet* dss =
      zone->fuseDependencies.getOrCreateDependentScriptSet(cx, this);
  if (!dss) {
    return false;
  }

  return dss->addScriptForFuse(this, script);
}

void js::InvalidatingRuntimeFuse::popFuse(JSContext* cx) {
  // Pop the fuse in the base class
  GuardFuse::popFuse(cx);
  // do invalidation.
  for (AllZonesIter z(cx->runtime()); !z.done(); z.next()) {
    // There's one dependent script set per fuse; just iterate over them all to
    // find the one we need (see comment on JS::Zone::fuseDependencies for
    // reasoning).
    for (auto& fd : z.get()->fuseDependencies) {
      fd.invalidateForFuse(cx, this);
    }
  }
}

void js::DependentScriptSet::invalidateForFuse(JSContext* cx,
                                               InvalidatingFuse* fuse) {
  if (associatedFuse != fuse) {
    return;
  }

  for (auto r = weakScripts.all(); !r.empty(); r.popFront()) {
    JSScript* script = r.front().get();
    // A script may have lost its ion script for other reasons
    // by the time this is invoked, so need to ensure it's still there
    // before calling invaidate.
    if (script->hasIonScript()) {
      JitSpew(jit::JitSpew_IonInvalidate, "Invalidating ion script %p",
              script->ionScript());
      js::jit::Invalidate(cx, script);
    }
  }

  // Scripts are invalidated, flush them.
  weakScripts.clear();
}

bool js::DependentScriptSet::addScriptForFuse(InvalidatingFuse* fuse,
                                              Handle<JSScript*> script) {
  MOZ_ASSERT(fuse == associatedFuse);

  WeakScriptSet::AddPtr p = weakScripts.lookupForAdd(script);
  if (!p) {
    if (!weakScripts.add(p, script)) {
      return false;
    }
  }

  // Script is already in the set, no need to re-add.
  return true;
}

js::DependentScriptSet* js::DependentScriptGroup::getOrCreateDependentScriptSet(
    JSContext* cx, js::InvalidatingFuse* fuse) {
  for (auto& dss : dependencies) {
    if (dss.associatedFuse == fuse) {
      return &dss;
    }
  }

  if (!dependencies.emplaceBack(cx, fuse)) {
    return nullptr;
  }

  auto& dss = dependencies.back();
  MOZ_ASSERT(dss.associatedFuse == fuse);
  return &dss;
}