1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef vm_Watchtower_h
8 #define vm_Watchtower_h
10 #include "js/TypeDecls.h"
11 #include "vm/NativeObject.h"
17 // Watchtower is a framework to hook into changes to certain objects. This gives
18 // us the ability to, for instance, invalidate caches or purge Warp code on
19 // object layout changes.
21 // Watchtower is only used for objects with certain ObjectFlags set on the
22 // Shape. This minimizes performance overhead for most objects.
24 // We currently use Watchtower for:
26 // - Invalidating the shape teleporting optimization. See the "Shape Teleporting
27 // Optimization" SMDOC comment in CacheIR.cpp.
29 // - Invalidating the MegamorphicCache, a property lookup cache for megamorphic
30 // property accesses. See the SMDOC comment in vm/Caches.h.
32 // There's also a testing mechanism that lets us write tests for Watchtower
33 // hooks. See setWatchtowerCallback and addWatchtowerTarget defined in
34 // TestingFunctions.cpp.
36 static bool watchPropertyAddSlow(JSContext
* cx
, Handle
<NativeObject
*> obj
,
38 static bool watchPropertyRemoveSlow(JSContext
* cx
, Handle
<NativeObject
*> obj
,
40 static bool watchPropertyChangeSlow(JSContext
* cx
, Handle
<NativeObject
*> obj
,
41 HandleId id
, PropertyFlags flags
);
42 template <AllowGC allowGC
>
43 static bool watchPropertyModificationSlow(
45 typename MaybeRooted
<NativeObject
*, allowGC
>::HandleType obj
,
46 typename MaybeRooted
<PropertyKey
, allowGC
>::HandleType id
);
47 static bool watchFreezeOrSealSlow(JSContext
* cx
, Handle
<NativeObject
*> obj
);
48 static bool watchProtoChangeSlow(JSContext
* cx
, HandleObject obj
);
49 static bool watchObjectSwapSlow(JSContext
* cx
, HandleObject a
,
53 static bool watchesPropertyAdd(NativeObject
* obj
) {
54 return obj
->hasAnyFlag(
55 {ObjectFlag::IsUsedAsPrototype
, ObjectFlag::UseWatchtowerTestingLog
});
57 static bool watchesPropertyRemove(NativeObject
* obj
) {
58 return obj
->hasAnyFlag(
59 {ObjectFlag::IsUsedAsPrototype
, ObjectFlag::GenerationCountedGlobal
,
60 ObjectFlag::UseWatchtowerTestingLog
, ObjectFlag::HasFuseProperty
});
62 static bool watchesPropertyChange(NativeObject
* obj
) {
63 return obj
->hasAnyFlag(
64 {ObjectFlag::IsUsedAsPrototype
, ObjectFlag::GenerationCountedGlobal
,
65 ObjectFlag::HasFuseProperty
, ObjectFlag::UseWatchtowerTestingLog
});
67 static bool watchesPropertyModification(NativeObject
* obj
) {
68 return obj
->hasAnyFlag(
69 {ObjectFlag::HasFuseProperty
, ObjectFlag::UseWatchtowerTestingLog
});
71 static bool watchesFreezeOrSeal(NativeObject
* obj
) {
72 return obj
->hasAnyFlag({ObjectFlag::UseWatchtowerTestingLog
});
74 static bool watchesProtoChange(JSObject
* obj
) {
75 return obj
->hasAnyFlag(
76 {ObjectFlag::IsUsedAsPrototype
, ObjectFlag::UseWatchtowerTestingLog
});
78 static bool watchesObjectSwap(JSObject
* a
, JSObject
* b
) {
79 auto watches
= [](JSObject
* obj
) {
80 return obj
->hasAnyFlag(
81 {ObjectFlag::IsUsedAsPrototype
, ObjectFlag::UseWatchtowerTestingLog
});
83 return watches(a
) || watches(b
);
86 static bool watchPropertyAdd(JSContext
* cx
, Handle
<NativeObject
*> obj
,
88 if (MOZ_LIKELY(!watchesPropertyAdd(obj
))) {
91 return watchPropertyAddSlow(cx
, obj
, id
);
93 static bool watchPropertyRemove(JSContext
* cx
, Handle
<NativeObject
*> obj
,
95 if (MOZ_LIKELY(!watchesPropertyRemove(obj
))) {
98 return watchPropertyRemoveSlow(cx
, obj
, id
);
100 static bool watchPropertyChange(JSContext
* cx
, Handle
<NativeObject
*> obj
,
101 HandleId id
, PropertyFlags flags
) {
102 if (MOZ_LIKELY(!watchesPropertyChange(obj
))) {
105 return watchPropertyChangeSlow(cx
, obj
, id
, flags
);
108 // Note: We can only watch property modification for regular object slots
109 // with an id, not reserved slots.
110 template <AllowGC allowGC
>
111 static bool watchPropertyModification(
113 typename MaybeRooted
<NativeObject
*, allowGC
>::HandleType obj
,
114 typename MaybeRooted
<PropertyKey
, allowGC
>::HandleType id
) {
115 if (MOZ_LIKELY(!watchesPropertyModification(obj
))) {
118 return watchPropertyModificationSlow
<allowGC
>(cx
, obj
, id
);
120 static bool watchFreezeOrSeal(JSContext
* cx
, Handle
<NativeObject
*> obj
) {
121 if (MOZ_LIKELY(!watchesFreezeOrSeal(obj
))) {
124 return watchFreezeOrSealSlow(cx
, obj
);
126 static bool watchProtoChange(JSContext
* cx
, HandleObject obj
) {
127 if (MOZ_LIKELY(!watchesProtoChange(obj
))) {
130 return watchProtoChangeSlow(cx
, obj
);
133 static bool watchObjectSwap(JSContext
* cx
, HandleObject a
, HandleObject b
) {
134 if (MOZ_LIKELY(!watchesObjectSwap(a
, b
))) {
137 return watchObjectSwapSlow(cx
, a
, b
);
143 #endif /* vm_Watchtower_h */