assert-scope.h 12.4 KB
Newer Older
1
// Copyright 2013 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_COMMON_ASSERT_SCOPE_H_
#define V8_COMMON_ASSERT_SCOPE_H_
7

8
#include <stdint.h>
9

10 11
#include <memory>

12
#include "src/base/macros.h"
13
#include "src/base/optional.h"
14
#include "src/base/platform/mutex.h"
15
#include "src/common/globals.h"
16 17 18 19

namespace v8 {
namespace internal {

20
// Forward declarations.
21 22 23
class Isolate;

enum PerThreadAssertType {
24
  SAFEPOINTS_ASSERT,
25 26 27
  HEAP_ALLOCATION_ASSERT,
  HANDLE_ALLOCATION_ASSERT,
  HANDLE_DEREFERENCE_ASSERT,
28
  CODE_DEPENDENCY_CHANGE_ASSERT,
29 30 31
  CODE_ALLOCATION_ASSERT,
  // Dummy type for disabling GC mole.
  GC_MOLE,
32 33
};

34 35
enum PerIsolateAssertType {
  JAVASCRIPT_EXECUTION_ASSERT,
36
  JAVASCRIPT_EXECUTION_THROWS,
37
  JAVASCRIPT_EXECUTION_DUMP,
38
  DEOPTIMIZATION_ASSERT,
39
  COMPILATION_ASSERT,
40
  NO_EXCEPTION_ASSERT,
41 42
};

43
template <PerThreadAssertType kType, bool kAllow>
44
class V8_NODISCARD PerThreadAssertScope {
45
 public:
46 47
  V8_EXPORT_PRIVATE PerThreadAssertScope();
  V8_EXPORT_PRIVATE ~PerThreadAssertScope();
48

49 50 51
  PerThreadAssertScope(const PerThreadAssertScope&) = delete;
  PerThreadAssertScope& operator=(const PerThreadAssertScope&) = delete;

52
  V8_EXPORT_PRIVATE static bool IsAllowed();
53

54 55
  void Release();

56
 private:
57
  base::Optional<uint32_t> old_data_;
58 59
};

60
template <PerIsolateAssertType kType, bool kAllow>
61
class V8_NODISCARD PerIsolateAssertScope {
62
 public:
63
  V8_EXPORT_PRIVATE explicit PerIsolateAssertScope(Isolate* isolate);
64 65
  PerIsolateAssertScope(const PerIsolateAssertScope&) = delete;
  PerIsolateAssertScope& operator=(const PerIsolateAssertScope&) = delete;
66
  V8_EXPORT_PRIVATE ~PerIsolateAssertScope();
67

68
  static bool IsAllowed(Isolate* isolate);
69

70 71 72 73 74
  V8_EXPORT_PRIVATE static void Open(Isolate* isolate,
                                     bool* was_execution_allowed);
  V8_EXPORT_PRIVATE static void Close(Isolate* isolate,
                                      bool was_execution_allowed);

75 76
 private:
  Isolate* isolate_;
77
  uint32_t old_data_;
78 79
};

80 81 82 83 84
template <typename... Scopes>
class CombinationAssertScope;

// Base case for CombinationAssertScope (equivalent to Scope).
template <typename Scope>
85
class V8_NODISCARD CombinationAssertScope<Scope> : public Scope {
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
 public:
  V8_EXPORT_PRIVATE static bool IsAllowed() {
    // Define IsAllowed() explicitly rather than with using Scope::IsAllowed, to
    // allow SFINAE removal of IsAllowed() when it's not defined (under debug).
    return Scope::IsAllowed();
  }
  using Scope::Release;
  using Scope::Scope;
};

// Inductive case for CombinationAssertScope.
template <typename Scope, typename... Scopes>
class CombinationAssertScope<Scope, Scopes...>
    : public Scope, public CombinationAssertScope<Scopes...> {
  using NextScopes = CombinationAssertScope<Scopes...>;

 public:
  // Constructor for per-thread scopes.
  V8_EXPORT_PRIVATE CombinationAssertScope() : Scope(), NextScopes() {}
  // Constructor for per-isolate scopes.
  V8_EXPORT_PRIVATE explicit CombinationAssertScope(Isolate* isolate)
      : Scope(isolate), NextScopes(isolate) {}

  V8_EXPORT_PRIVATE static bool IsAllowed() {
    return Scope::IsAllowed() && NextScopes::IsAllowed();
  }

  void Release() {
    // Release in reverse order.
    NextScopes::Release();
    Scope::Release();
  }
};

template <PerThreadAssertType kType, bool kAllow>
121
#ifdef DEBUG
122 123
class PerThreadAssertScopeDebugOnly
    : public PerThreadAssertScope<kType, kAllow> {
124
#else
125
class V8_NODISCARD PerThreadAssertScopeDebugOnly {
126
 public:
127
  PerThreadAssertScopeDebugOnly() {  // NOLINT (modernize-use-equals-default)
128 129
    // Define a constructor to avoid unused variable warnings.
  }
130
  void Release() {}
131 132 133
#endif
};

134
template <PerIsolateAssertType kType, bool kAllow>
135
#ifdef DEBUG
136
class PerIsolateAssertScopeDebugOnly
137
    : public PerIsolateAssertScope<kType, kAllow> {
138 139
 public:
  explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate)
140
      : PerIsolateAssertScope<kType, kAllow>(isolate) {}
141
#else
142
class V8_NODISCARD PerIsolateAssertScopeDebugOnly {
143
 public:
144
  explicit PerIsolateAssertScopeDebugOnly(Isolate* isolate) {}
145 146 147
#endif
};

148 149
// Per-thread assert scopes.

150
// Scope to document where we do not expect handles to be created.
151 152
using DisallowHandleAllocation =
    PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, false>;
153 154

// Scope to introduce an exception to DisallowHandleAllocation.
155 156
using AllowHandleAllocation =
    PerThreadAssertScopeDebugOnly<HANDLE_ALLOCATION_ASSERT, true>;
157

158 159 160
// Scope to document where we do not expect safepoints to be entered.
using DisallowSafepoints =
    PerThreadAssertScopeDebugOnly<SAFEPOINTS_ASSERT, false>;
161

162 163
// Scope to introduce an exception to DisallowSafepoints.
using AllowSafepoints = PerThreadAssertScopeDebugOnly<SAFEPOINTS_ASSERT, true>;
164

165
// Scope to document where we do not expect any allocation.
166 167
using DisallowHeapAllocation =
    PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, false>;
168 169

// Scope to introduce an exception to DisallowHeapAllocation.
170 171
using AllowHeapAllocation =
    PerThreadAssertScopeDebugOnly<HEAP_ALLOCATION_ASSERT, true>;
172 173

// Scope to document where we do not expect any handle dereferences.
174 175
using DisallowHandleDereference =
    PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, false>;
176 177

// Scope to introduce an exception to DisallowHandleDereference.
178 179
using AllowHandleDereference =
    PerThreadAssertScopeDebugOnly<HANDLE_DEREFERENCE_ASSERT, true>;
180

181
// Scope to document where we do not expect code dependencies to change.
182 183
using DisallowCodeDependencyChange =
    PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, false>;
184

185
// Scope to introduce an exception to DisallowCodeDependencyChange.
186 187
using AllowCodeDependencyChange =
    PerThreadAssertScopeDebugOnly<CODE_DEPENDENCY_CHANGE_ASSERT, true>;
188

189 190 191 192 193 194 195 196
// Scope to document where we do not expect code to be allocated.
using DisallowCodeAllocation =
    PerThreadAssertScopeDebugOnly<CODE_ALLOCATION_ASSERT, false>;

// Scope to introduce an exception to DisallowCodeAllocation.
using AllowCodeAllocation =
    PerThreadAssertScopeDebugOnly<CODE_ALLOCATION_ASSERT, true>;

197 198 199 200
// Scope to document where we do not expect garbage collections. It differs from
// DisallowHeapAllocation by also forbidding safepoints.
using DisallowGarbageCollection =
    CombinationAssertScope<DisallowSafepoints, DisallowHeapAllocation>;
201 202 203 204 205

// Scope to skip gc mole verification in places where we do tricky raw
// work.
using DisableGCMole = PerThreadAssertScopeDebugOnly<GC_MOLE, false>;

206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
// The DISALLOW_GARBAGE_COLLECTION macro can be used to define a
// DisallowGarbageCollection field in classes that isn't present in release
// builds.
#ifdef DEBUG
#define DISALLOW_GARBAGE_COLLECTION(name) DisallowGarbageCollection name;
#else
#define DISALLOW_GARBAGE_COLLECTION(name)
#endif

// Scope to introduce an exception to DisallowGarbageCollection.
using AllowGarbageCollection =
    CombinationAssertScope<AllowSafepoints, AllowHeapAllocation>;

// Scope to document where we do not expect any access to the heap.
using DisallowHeapAccess =
    CombinationAssertScope<DisallowCodeDependencyChange,
                           DisallowHandleDereference, DisallowHandleAllocation,
                           DisallowHeapAllocation>;

// Scope to introduce an exception to DisallowHeapAccess.
using AllowHeapAccess =
    CombinationAssertScope<AllowCodeDependencyChange, AllowHandleDereference,
                           AllowHandleAllocation, AllowHeapAllocation>;
229 230 231 232 233 234 235 236 237

class DisallowHeapAccessIf {
 public:
  explicit DisallowHeapAccessIf(bool condition) {
    if (condition) maybe_disallow_.emplace();
  }

 private:
  base::Optional<DisallowHeapAccess> maybe_disallow_;
238
};
239

240
// Like MutexGuard but also asserts that no garbage collection happens while
241
// we're holding the mutex.
242
class V8_NODISCARD NoGarbageCollectionMutexGuard {
243
 public:
244 245
  explicit NoGarbageCollectionMutexGuard(base::Mutex* mutex)
      : guard_(mutex), mutex_(mutex), no_gc_(new DisallowGarbageCollection()) {}
246 247 248 249 250 251 252

  void Unlock() {
    mutex_->Unlock();
    no_gc_.reset();
  }
  void Lock() {
    mutex_->Lock();
253
    no_gc_.reset(new DisallowGarbageCollection());
254 255 256 257 258
  }

 private:
  base::MutexGuard guard_;
  base::Mutex* mutex_;
259
  std::unique_ptr<DisallowGarbageCollection> no_gc_;
260 261
};

262 263 264
// Per-isolate assert scopes.

// Scope to document where we do not expect javascript execution.
265 266
using DisallowJavascriptExecution =
    PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>;
267 268

// Scope to introduce an exception to DisallowJavascriptExecution.
269 270
using AllowJavascriptExecution =
    PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>;
271

272
// Scope to document where we do not expect javascript execution (debug only)
273 274
using DisallowJavascriptExecutionDebugOnly =
    PerIsolateAssertScopeDebugOnly<JAVASCRIPT_EXECUTION_ASSERT, false>;
275 276

// Scope to introduce an exception to DisallowJavascriptExecutionDebugOnly.
277 278
using AllowJavascriptExecutionDebugOnly =
    PerIsolateAssertScopeDebugOnly<JAVASCRIPT_EXECUTION_ASSERT, true>;
279

280
// Scope in which javascript execution leads to exception being thrown.
281 282
using ThrowOnJavascriptExecution =
    PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>;
283 284

// Scope to introduce an exception to ThrowOnJavascriptExecution.
285 286
using NoThrowOnJavascriptExecution =
    PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>;
287

288
// Scope in which javascript execution causes dumps.
289 290
using DumpOnJavascriptExecution =
    PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, false>;
291 292

// Scope in which javascript execution causes dumps.
293 294
using NoDumpOnJavascriptExecution =
    PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, true>;
295

296
// Scope to document where we do not expect deoptimization.
297 298
using DisallowDeoptimization =
    PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, false>;
299 300

// Scope to introduce an exception to DisallowDeoptimization.
301 302
using AllowDeoptimization =
    PerIsolateAssertScopeDebugOnly<DEOPTIMIZATION_ASSERT, true>;
303

304
// Scope to document where we do not expect deoptimization.
305 306
using DisallowCompilation =
    PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, false>;
307 308

// Scope to introduce an exception to DisallowDeoptimization.
309 310
using AllowCompilation =
    PerIsolateAssertScopeDebugOnly<COMPILATION_ASSERT, true>;
311 312

// Scope to document where we do not expect exceptions.
313 314
using DisallowExceptions =
    PerIsolateAssertScopeDebugOnly<NO_EXCEPTION_ASSERT, false>;
315 316

// Scope to introduce an exception to DisallowExceptions.
317 318
using AllowExceptions =
    PerIsolateAssertScopeDebugOnly<NO_EXCEPTION_ASSERT, true>;
319 320 321 322

// Explicit instantiation declarations.
extern template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, false>;
extern template class PerThreadAssertScope<HEAP_ALLOCATION_ASSERT, true>;
323 324
extern template class PerThreadAssertScope<SAFEPOINTS_ASSERT, false>;
extern template class PerThreadAssertScope<SAFEPOINTS_ASSERT, true>;
325 326 327 328 329 330 331
extern template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, false>;
extern template class PerThreadAssertScope<HANDLE_ALLOCATION_ASSERT, true>;
extern template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, false>;
extern template class PerThreadAssertScope<HANDLE_DEREFERENCE_ASSERT, true>;
extern template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT,
                                           false>;
extern template class PerThreadAssertScope<CODE_DEPENDENCY_CHANGE_ASSERT, true>;
332 333
extern template class PerThreadAssertScope<CODE_ALLOCATION_ASSERT, false>;
extern template class PerThreadAssertScope<CODE_ALLOCATION_ASSERT, true>;
334
extern template class PerThreadAssertScope<GC_MOLE, false>;
335 336 337 338 339 340 341 342 343 344 345 346 347 348

extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, false>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_ASSERT, true>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, false>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_THROWS, true>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, false>;
extern template class PerIsolateAssertScope<JAVASCRIPT_EXECUTION_DUMP, true>;
extern template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, false>;
extern template class PerIsolateAssertScope<DEOPTIMIZATION_ASSERT, true>;
extern template class PerIsolateAssertScope<COMPILATION_ASSERT, false>;
extern template class PerIsolateAssertScope<COMPILATION_ASSERT, true>;
extern template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, false>;
extern template class PerIsolateAssertScope<NO_EXCEPTION_ASSERT, true>;

349 350
}  // namespace internal
}  // namespace v8
351

352
#endif  // V8_COMMON_ASSERT_SCOPE_H_