• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_TORQUE_CONTEXTUAL_H_
6 #define V8_TORQUE_CONTEXTUAL_H_
7 
8 #include <type_traits>
9 
10 #include "src/base/macros.h"
11 #include "src/base/platform/platform.h"
12 
13 namespace v8 {
14 namespace internal {
15 namespace torque {
16 
17 // {ContextualVariable} provides a clean alternative to a global variable.
18 // The contextual variable is mutable, and supports managing the value of
19 // a variable in a well-nested fashion via the {Scope} class.
20 // {ContextualVariable} only stores a pointer to the current value, which
21 // is stored in a {Scope} object. The most recent value can be retrieved
22 // via Get(). Because only {Scope} has actual storage, there must be at
23 // least one active {Scope} (i.e. in a surrounding C++ scope), whenever Get()
24 // is called.
25 // Note that contextual variables must only be used from the same thread,
26 // i.e. {Scope} and Get() have to be in the same thread.
27 template <class Derived, class VarType>
28 class ContextualVariable {
29  public:
30   using VariableType = VarType;
31 
32   // A {Scope} contains a new object of type {VarType} and gives
33   // ContextualVariable::Get() access to it. Upon destruction, the contextual
34   // variable is restored to the state before the {Scope} was created. Scopes
35   // have to follow a stack discipline:  A {Scope} has to be destructed before
36   // any older scope is destructed.
37   class Scope {
38    public:
39     template <class... Args>
Scope(Args &&...args)40     explicit Scope(Args&&... args)
41         : current_(std::forward<Args>(args)...), previous_(Top()) {
42       Top() = &current_;
43     }
~Scope()44     ~Scope() {
45       // Ensure stack discipline.
46       DCHECK_EQ(&current_, Top());
47       Top() = previous_;
48     }
49 
50    private:
51     VarType current_;
52     VarType* previous_;
53 
54     static_assert(std::is_base_of<ContextualVariable, Derived>::value,
55                   "Curiously Recurring Template Pattern");
56 
57     DISALLOW_NEW_AND_DELETE();
58     DISALLOW_COPY_AND_ASSIGN(Scope);
59   };
60 
61   // Access the most recent active {Scope}. There has to be an active {Scope}
62   // for this contextual variable.
Get()63   static VarType& Get() {
64     DCHECK_NOT_NULL(Top());
65     return *Top();
66   }
67 
68  private:
69   V8_EXPORT_PRIVATE static VarType*& Top();
70 };
71 
72 // Usage: DECLARE_CONTEXTUAL_VARIABLE(VarName, VarType)
73 #define DECLARE_CONTEXTUAL_VARIABLE(VarName, ...) \
74   struct VarName                                  \
75       : v8::internal::torque::ContextualVariable<VarName, __VA_ARGS__> {};
76 
77 #define DEFINE_CONTEXTUAL_VARIABLE(VarName)                   \
78   template <>                                                 \
79   V8_EXPORT_PRIVATE VarName::VariableType*&                   \
80   ContextualVariable<VarName, VarName::VariableType>::Top() { \
81     static thread_local VarName::VariableType* top = nullptr; \
82     return top;                                               \
83   }
84 
85 // By inheriting from {ContextualClass} a class can become a contextual variable
86 // of itself, which is very similar to a singleton.
87 template <class T>
88 using ContextualClass = ContextualVariable<T, T>;
89 
90 }  // namespace torque
91 }  // namespace internal
92 }  // namespace v8
93 
94 #endif  // V8_TORQUE_CONTEXTUAL_H_
95