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