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