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() = ¤t_; 43 } ~Scope()44 ~Scope() { 45 // Ensure stack discipline. 46 DCHECK_EQ(¤t_, 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