1// Copyright 2011 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_HANDLES_H_
6#define V8_HANDLES_H_
7
8#include "src/objects.h"
9
10namespace v8 {
11namespace internal {
12
13// A Handle can be converted into a MaybeHandle. Converting a MaybeHandle
14// into a Handle requires checking that it does not point to NULL.  This
15// ensures NULL checks before use.
16// Do not use MaybeHandle as argument type.
17
18template<typename T>
19class MaybeHandle {
20 public:
21  INLINE(MaybeHandle()) : location_(NULL) { }
22
23  // Constructor for handling automatic up casting from Handle.
24  // Ex. Handle<JSArray> can be passed when MaybeHandle<Object> is expected.
25  template <class S> MaybeHandle(Handle<S> handle) {
26#ifdef DEBUG
27    T* a = NULL;
28    S* b = NULL;
29    a = b;  // Fake assignment to enforce type checks.
30    USE(a);
31#endif
32    this->location_ = reinterpret_cast<T**>(handle.location());
33  }
34
35  // Constructor for handling automatic up casting.
36  // Ex. MaybeHandle<JSArray> can be passed when Handle<Object> is expected.
37  template <class S> MaybeHandle(MaybeHandle<S> maybe_handle) {
38#ifdef DEBUG
39    T* a = NULL;
40    S* b = NULL;
41    a = b;  // Fake assignment to enforce type checks.
42    USE(a);
43#endif
44    location_ = reinterpret_cast<T**>(maybe_handle.location_);
45  }
46
47  INLINE(void Assert() const) { DCHECK(location_ != NULL); }
48  INLINE(void Check() const) { CHECK(location_ != NULL); }
49
50  INLINE(Handle<T> ToHandleChecked()) const {
51    Check();
52    return Handle<T>(location_);
53  }
54
55  // Convert to a Handle with a type that can be upcasted to.
56  template <class S> INLINE(bool ToHandle(Handle<S>* out)) {
57    if (location_ == NULL) {
58      *out = Handle<T>::null();
59      return false;
60    } else {
61      *out = Handle<T>(location_);
62      return true;
63    }
64  }
65
66  bool is_null() const { return location_ == NULL; }
67
68 protected:
69  T** location_;
70
71  // MaybeHandles of different classes are allowed to access each
72  // other's location_.
73  template<class S> friend class MaybeHandle;
74};
75
76// ----------------------------------------------------------------------------
77// A Handle provides a reference to an object that survives relocation by
78// the garbage collector.
79// Handles are only valid within a HandleScope.
80// When a handle is created for an object a cell is allocated in the heap.
81
82template<typename T>
83class Handle {
84 public:
85  INLINE(explicit Handle(T** location)) { location_ = location; }
86  INLINE(explicit Handle(T* obj));
87  INLINE(Handle(T* obj, Isolate* isolate));
88
89  // TODO(yangguo): Values that contain empty handles should be declared as
90  // MaybeHandle to force validation before being used as handles.
91  INLINE(Handle()) : location_(NULL) { }
92
93  // Constructor for handling automatic up casting.
94  // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
95  template <class S> Handle(Handle<S> handle) {
96#ifdef DEBUG
97    T* a = NULL;
98    S* b = NULL;
99    a = b;  // Fake assignment to enforce type checks.
100    USE(a);
101#endif
102    location_ = reinterpret_cast<T**>(handle.location_);
103  }
104
105  INLINE(T* operator->() const) { return operator*(); }
106
107  // Check if this handle refers to the exact same object as the other handle.
108  INLINE(bool is_identical_to(const Handle<T> other) const);
109
110  // Provides the C++ dereference operator.
111  INLINE(T* operator*() const);
112
113  // Returns the address to where the raw pointer is stored.
114  INLINE(T** location() const);
115
116  template <class S> static Handle<T> cast(Handle<S> that) {
117    T::cast(*reinterpret_cast<T**>(that.location_));
118    return Handle<T>(reinterpret_cast<T**>(that.location_));
119  }
120
121  // TODO(yangguo): Values that contain empty handles should be declared as
122  // MaybeHandle to force validation before being used as handles.
123  static Handle<T> null() { return Handle<T>(); }
124  bool is_null() const { return location_ == NULL; }
125
126  // Closes the given scope, but lets this handle escape. See
127  // implementation in api.h.
128  inline Handle<T> EscapeFrom(v8::EscapableHandleScope* scope);
129
130#ifdef DEBUG
131  enum DereferenceCheckMode { INCLUDE_DEFERRED_CHECK, NO_DEFERRED_CHECK };
132
133  bool IsDereferenceAllowed(DereferenceCheckMode mode) const;
134#endif  // DEBUG
135
136 private:
137  T** location_;
138
139  // Handles of different classes are allowed to access each other's location_.
140  template<class S> friend class Handle;
141};
142
143
144// Convenience wrapper.
145template<class T>
146inline Handle<T> handle(T* t, Isolate* isolate) {
147  return Handle<T>(t, isolate);
148}
149
150
151// Convenience wrapper.
152template<class T>
153inline Handle<T> handle(T* t) {
154  return Handle<T>(t, t->GetIsolate());
155}
156
157
158// Key comparison function for Map handles.
159inline bool operator<(const Handle<Map>& lhs, const Handle<Map>& rhs) {
160  // This is safe because maps don't move.
161  return *lhs < *rhs;
162}
163
164
165class DeferredHandles;
166class HandleScopeImplementer;
167
168
169// A stack-allocated class that governs a number of local handles.
170// After a handle scope has been created, all local handles will be
171// allocated within that handle scope until either the handle scope is
172// deleted or another handle scope is created.  If there is already a
173// handle scope and a new one is created, all allocations will take
174// place in the new handle scope until it is deleted.  After that,
175// new handles will again be allocated in the original handle scope.
176//
177// After the handle scope of a local handle has been deleted the
178// garbage collector will no longer track the object stored in the
179// handle and may deallocate it.  The behavior of accessing a handle
180// for which the handle scope has been deleted is undefined.
181class HandleScope {
182 public:
183  explicit inline HandleScope(Isolate* isolate);
184
185  inline ~HandleScope();
186
187  // Counts the number of allocated handles.
188  static int NumberOfHandles(Isolate* isolate);
189
190  // Creates a new handle with the given value.
191  template <typename T>
192  static inline T** CreateHandle(Isolate* isolate, T* value);
193
194  // Deallocates any extensions used by the current scope.
195  static void DeleteExtensions(Isolate* isolate);
196
197  static Address current_next_address(Isolate* isolate);
198  static Address current_limit_address(Isolate* isolate);
199  static Address current_level_address(Isolate* isolate);
200
201  // Closes the HandleScope (invalidating all handles
202  // created in the scope of the HandleScope) and returns
203  // a Handle backed by the parent scope holding the
204  // value of the argument handle.
205  template <typename T>
206  Handle<T> CloseAndEscape(Handle<T> handle_value);
207
208  Isolate* isolate() { return isolate_; }
209
210 private:
211  // Prevent heap allocation or illegal handle scopes.
212  HandleScope(const HandleScope&);
213  void operator=(const HandleScope&);
214  void* operator new(size_t size);
215  void operator delete(void* size_t);
216
217  Isolate* isolate_;
218  Object** prev_next_;
219  Object** prev_limit_;
220
221  // Close the handle scope resetting limits to a previous state.
222  static inline void CloseScope(Isolate* isolate,
223                                Object** prev_next,
224                                Object** prev_limit);
225
226  // Extend the handle scope making room for more handles.
227  static internal::Object** Extend(Isolate* isolate);
228
229#ifdef ENABLE_HANDLE_ZAPPING
230  // Zaps the handles in the half-open interval [start, end).
231  static void ZapRange(Object** start, Object** end);
232#endif
233
234  friend class v8::HandleScope;
235  friend class v8::internal::DeferredHandles;
236  friend class v8::internal::HandleScopeImplementer;
237  friend class v8::internal::Isolate;
238};
239
240
241class DeferredHandles;
242
243
244class DeferredHandleScope {
245 public:
246  explicit DeferredHandleScope(Isolate* isolate);
247  // The DeferredHandles object returned stores the Handles created
248  // since the creation of this DeferredHandleScope.  The Handles are
249  // alive as long as the DeferredHandles object is alive.
250  DeferredHandles* Detach();
251  ~DeferredHandleScope();
252
253 private:
254  Object** prev_limit_;
255  Object** prev_next_;
256  HandleScopeImplementer* impl_;
257
258#ifdef DEBUG
259  bool handles_detached_;
260  int prev_level_;
261#endif
262
263  friend class HandleScopeImplementer;
264};
265
266
267// Seal off the current HandleScope so that new handles can only be created
268// if a new HandleScope is entered.
269class SealHandleScope BASE_EMBEDDED {
270 public:
271#ifndef DEBUG
272  explicit SealHandleScope(Isolate* isolate) {}
273  ~SealHandleScope() {}
274#else
275  explicit inline SealHandleScope(Isolate* isolate);
276  inline ~SealHandleScope();
277 private:
278  Isolate* isolate_;
279  Object** limit_;
280  int level_;
281#endif
282};
283
284struct HandleScopeData {
285  internal::Object** next;
286  internal::Object** limit;
287  int level;
288
289  void Initialize() {
290    next = limit = NULL;
291    level = 0;
292  }
293};
294
295} }  // namespace v8::internal
296
297#endif  // V8_HANDLES_H_
298