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 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 
Value()51     VarType& Value() { return value_; }
52 
53    private:
54     VarType value_;
55     Scope* previous_;
56 
57     static_assert(std::is_base_of<ContextualVariable, Derived>::value,
58                   "Curiously Recurring Template Pattern");
59 
60     DISALLOW_NEW_AND_DELETE()
61     DISALLOW_COPY_AND_ASSIGN(Scope);
62   };
63 
64   // Access the most recent active {Scope}. There has to be an active {Scope}
65   // for this contextual variable.
Get()66   static VarType& Get() {
67     DCHECK_NOT_NULL(Top());
68     return Top()->Value();
69   }
70 
71  private:
72   template <class T>
73   friend V8_EXPORT_PRIVATE typename T::Scope*& ContextualVariableTop();
Top()74   static Scope*& Top() { return ContextualVariableTop<Derived>(); }
75 
HasScope()76   static bool HasScope() { return Top() != nullptr; }
77   friend class MessageBuilder;
78 };
79 
80 // Usage: DECLARE_CONTEXTUAL_VARIABLE(VarName, VarType)
81 #define DECLARE_CONTEXTUAL_VARIABLE(VarName, ...) \
82   struct VarName                                  \
83       : v8::internal::torque::ContextualVariable<VarName, __VA_ARGS__> {}
84 
85 #define DEFINE_CONTEXTUAL_VARIABLE(VarName)                             \
86   template <>                                                           \
87   V8_EXPORT_PRIVATE VarName::Scope*& ContextualVariableTop<VarName>() { \
88     static thread_local VarName::Scope* top = nullptr;                  \
89     return top;                                                         \
90   }
91 
92 // By inheriting from {ContextualClass} a class can become a contextual variable
93 // of itself, which is very similar to a singleton.
94 template <class T>
95 using ContextualClass = ContextualVariable<T, T>;
96 
97 }  // namespace torque
98 }  // namespace internal
99 }  // namespace v8
100 
101 #endif  // V8_TORQUE_CONTEXTUAL_H_
102