contextual.h 3.43 KB
Newer Older
1 2 3 4 5 6 7 8 9
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_TORQUE_CONTEXTUAL_H_
#define V8_TORQUE_CONTEXTUAL_H_

#include <type_traits>

10 11 12
#include "src/base/macros.h"
#include "src/base/platform/platform.h"

13 14 15 16
namespace v8 {
namespace internal {
namespace torque {

17
template <class Variable>
18
V8_EXPORT_PRIVATE typename Variable::Scope*& ContextualVariableTop();
19

20 21 22 23 24 25 26 27 28 29
// {ContextualVariable} provides a clean alternative to a global variable.
// The contextual variable is mutable, and supports managing the value of
// a variable in a well-nested fashion via the {Scope} class.
// {ContextualVariable} only stores a pointer to the current value, which
// is stored in a {Scope} object. The most recent value can be retrieved
// via Get(). Because only {Scope} has actual storage, there must be at
// least one active {Scope} (i.e. in a surrounding C++ scope), whenever Get()
// is called.
// Note that contextual variables must only be used from the same thread,
// i.e. {Scope} and Get() have to be in the same thread.
30 31 32
template <class Derived, class VarType>
class ContextualVariable {
 public:
33
  // A {Scope} contains a new object of type {VarType} and gives
34 35 36 37 38 39
  // ContextualVariable::Get() access to it. Upon destruction, the contextual
  // variable is restored to the state before the {Scope} was created. Scopes
  // have to follow a stack discipline:  A {Scope} has to be destructed before
  // any older scope is destructed.
  class Scope {
   public:
40 41
    template <class... Args>
    explicit Scope(Args&&... args)
42 43
        : value_(std::forward<Args>(args)...), previous_(Top()) {
      Top() = this;
44 45 46
    }
    ~Scope() {
      // Ensure stack discipline.
47
      DCHECK_EQ(this, Top());
48
      Top() = previous_;
49 50
    }

51 52
    VarType& Value() { return value_; }

53
   private:
54 55
    VarType value_;
    Scope* previous_;
56 57 58

    static_assert(std::is_base_of<ContextualVariable, Derived>::value,
                  "Curiously Recurring Template Pattern");
59

60
    DISALLOW_NEW_AND_DELETE()
61
    DISALLOW_COPY_AND_ASSIGN(Scope);
62 63 64 65 66
  };

  // Access the most recent active {Scope}. There has to be an active {Scope}
  // for this contextual variable.
  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();
74
  static Scope*& Top() { return ContextualVariableTop<Derived>(); }
75

76
  static bool HasScope() { return Top() != nullptr; }
77
  friend class MessageBuilder;
78 79 80 81 82
};

// Usage: DECLARE_CONTEXTUAL_VARIABLE(VarName, VarType)
#define DECLARE_CONTEXTUAL_VARIABLE(VarName, ...) \
  struct VarName                                  \
83
      : v8::internal::torque::ContextualVariable<VarName, __VA_ARGS__> {}
84

85 86 87 88 89
#define DEFINE_CONTEXTUAL_VARIABLE(VarName)                             \
  template <>                                                           \
  V8_EXPORT_PRIVATE VarName::Scope*& ContextualVariableTop<VarName>() { \
    static thread_local VarName::Scope* top = nullptr;                  \
    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 95 96 97 98 99 100 101
template <class T>
using ContextualClass = ContextualVariable<T, T>;

}  // namespace torque
}  // namespace internal
}  // namespace v8

#endif  // V8_TORQUE_CONTEXTUAL_H_