• 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 template <class Variable>
18 V8_EXPORT_PRIVATE typename Variable::Scope*& ContextualVariableTop();
19 
20 // {ContextualVariable} provides a clean alternative to a global variable.
21 // The contextual variable is mutable, and supports managing the value of
22 // a variable in a well-nested fashion via the {Scope} class.
23 // {ContextualVariable} only stores a pointer to the current value, which
24 // is stored in a {Scope} object. The most recent value can be retrieved
25 // via Get(). Because only {Scope} has actual storage, there must be at
26 // least one active {Scope} (i.e. in a surrounding C++ scope), whenever Get()
27 // is called.
28 // Note that contextual variables must only be used from the same thread,
29 // i.e. {Scope} and Get() have to be in the same thread.
30 template <class Derived, class VarType>
31 class ContextualVariable {
32  public:
33   // A {Scope} contains a new object of type {VarType} and gives
34   // ContextualVariable::Get() access to it. Upon destruction, the contextual
35   // variable is restored to the state before the {Scope} was created. Scopes
36   // have to follow a stack discipline:  A {Scope} has to be destructed before
37   // any older scope is destructed.
38   class V8_NODISCARD Scope {
39    public:
40     template <class... Args>
Scope(Args &&...args)41     explicit Scope(Args&&... args)
42         : value_(std::forward<Args>(args)...), previous_(Top()) {
43       Top() = this;
44     }
~Scope()45     ~Scope() {
46       // Ensure stack discipline.
47       DCHECK_EQ(this, Top());
48       Top() = previous_;
49     }
50     Scope(const Scope&) = delete;
51     Scope& operator=(const Scope&) = delete;
52 
Value()53     VarType& Value() { return value_; }
54 
55    private:
56     VarType value_;
57     Scope* previous_;
58 
59     static_assert(std::is_base_of<ContextualVariable, Derived>::value,
60                   "Curiously Recurring Template Pattern");
61 
62     DISALLOW_NEW_AND_DELETE()
63   };
64 
65   // Access the most recent active {Scope}. There has to be an active {Scope}
66   // for this contextual variable.
Get()67   static VarType& Get() {
68     DCHECK_NOT_NULL(Top());
69     return Top()->Value();
70   }
71 
72  private:
73   template <class T>
74   friend V8_EXPORT_PRIVATE typename T::Scope*& ContextualVariableTop();
Top()75   static Scope*& Top() { return ContextualVariableTop<Derived>(); }
76 
HasScope()77   static bool HasScope() { return Top() != nullptr; }
78   friend class MessageBuilder;
79 };
80 
81 // Usage: DECLARE_CONTEXTUAL_VARIABLE(VarName, VarType)
82 #define DECLARE_CONTEXTUAL_VARIABLE(VarName, ...) \
83   struct VarName                                  \
84       : v8::internal::torque::ContextualVariable<VarName, __VA_ARGS__> {}
85 
86 #define DEFINE_CONTEXTUAL_VARIABLE(VarName)                             \
87   template <>                                                           \
88   V8_EXPORT_PRIVATE VarName::Scope*& ContextualVariableTop<VarName>() { \
89     static thread_local VarName::Scope* top = nullptr;                  \
90     return top;                                                         \
91   }
92 
93 // By inheriting from {ContextualClass} a class can become a contextual variable
94 // of itself, which is very similar to a singleton.
95 template <class T>
96 using ContextualClass = ContextualVariable<T, T>;
97 
98 }  // namespace torque
99 }  // namespace internal
100 }  // namespace v8
101 
102 #endif  // V8_TORQUE_CONTEXTUAL_H_
103