1// Copyright 2012 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#include "src/handles.h"
6
7#include "src/address-map.h"
8#include "src/base/logging.h"
9#include "src/identity-map.h"
10#include "src/objects-inl.h"
11
12namespace v8 {
13namespace internal {
14
15#ifdef DEBUG
16bool HandleBase::IsDereferenceAllowed(DereferenceCheckMode mode) const {
17  DCHECK_NOT_NULL(location_);
18  Object* object = *location_;
19  if (object->IsSmi()) return true;
20  HeapObject* heap_object = HeapObject::cast(object);
21  Heap* heap = heap_object->GetHeap();
22  Object** roots_array_start = heap->roots_array_start();
23  if (roots_array_start <= location_ &&
24      location_ < roots_array_start + Heap::kStrongRootListLength &&
25      heap->RootCanBeTreatedAsConstant(
26          static_cast<Heap::RootListIndex>(location_ - roots_array_start))) {
27    return true;
28  }
29  if (!AllowHandleDereference::IsAllowed()) return false;
30  if (mode == INCLUDE_DEFERRED_CHECK &&
31      !AllowDeferredHandleDereference::IsAllowed()) {
32    // Accessing cells, maps and internalized strings is safe.
33    if (heap_object->IsCell()) return true;
34    if (heap_object->IsMap()) return true;
35    if (heap_object->IsInternalizedString()) return true;
36    return !heap->isolate()->IsDeferredHandle(location_);
37  }
38  return true;
39}
40#endif
41
42
43int HandleScope::NumberOfHandles(Isolate* isolate) {
44  HandleScopeImplementer* impl = isolate->handle_scope_implementer();
45  int n = impl->blocks()->length();
46  if (n == 0) return 0;
47  return ((n - 1) * kHandleBlockSize) + static_cast<int>(
48      (isolate->handle_scope_data()->next - impl->blocks()->last()));
49}
50
51
52Object** HandleScope::Extend(Isolate* isolate) {
53  HandleScopeData* current = isolate->handle_scope_data();
54
55  Object** result = current->next;
56
57  DCHECK(result == current->limit);
58  // Make sure there's at least one scope on the stack and that the
59  // top of the scope stack isn't a barrier.
60  if (!Utils::ApiCheck(current->level != current->sealed_level,
61                       "v8::HandleScope::CreateHandle()",
62                       "Cannot create a handle without a HandleScope")) {
63    return NULL;
64  }
65  HandleScopeImplementer* impl = isolate->handle_scope_implementer();
66  // If there's more room in the last block, we use that. This is used
67  // for fast creation of scopes after scope barriers.
68  if (!impl->blocks()->is_empty()) {
69    Object** limit = &impl->blocks()->last()[kHandleBlockSize];
70    if (current->limit != limit) {
71      current->limit = limit;
72      DCHECK(limit - current->next < kHandleBlockSize);
73    }
74  }
75
76  // If we still haven't found a slot for the handle, we extend the
77  // current handle scope by allocating a new handle block.
78  if (result == current->limit) {
79    // If there's a spare block, use it for growing the current scope.
80    result = impl->GetSpareOrNewBlock();
81    // Add the extension to the global list of blocks, but count the
82    // extension as part of the current scope.
83    impl->blocks()->Add(result);
84    current->limit = &result[kHandleBlockSize];
85  }
86
87  return result;
88}
89
90
91void HandleScope::DeleteExtensions(Isolate* isolate) {
92  HandleScopeData* current = isolate->handle_scope_data();
93  isolate->handle_scope_implementer()->DeleteExtensions(current->limit);
94}
95
96
97#ifdef ENABLE_HANDLE_ZAPPING
98void HandleScope::ZapRange(Object** start, Object** end) {
99  DCHECK(end - start <= kHandleBlockSize);
100  for (Object** p = start; p != end; p++) {
101    *reinterpret_cast<Address*>(p) = kHandleZapValue;
102  }
103}
104#endif
105
106
107Address HandleScope::current_level_address(Isolate* isolate) {
108  return reinterpret_cast<Address>(&isolate->handle_scope_data()->level);
109}
110
111
112Address HandleScope::current_next_address(Isolate* isolate) {
113  return reinterpret_cast<Address>(&isolate->handle_scope_data()->next);
114}
115
116
117Address HandleScope::current_limit_address(Isolate* isolate) {
118  return reinterpret_cast<Address>(&isolate->handle_scope_data()->limit);
119}
120
121CanonicalHandleScope::CanonicalHandleScope(Isolate* isolate)
122    : isolate_(isolate), zone_(isolate->allocator()) {
123  HandleScopeData* handle_scope_data = isolate_->handle_scope_data();
124  prev_canonical_scope_ = handle_scope_data->canonical_scope;
125  handle_scope_data->canonical_scope = this;
126  root_index_map_ = new RootIndexMap(isolate);
127  identity_map_ = new IdentityMap<Object**>(isolate->heap(), &zone_);
128  canonical_level_ = handle_scope_data->level;
129}
130
131
132CanonicalHandleScope::~CanonicalHandleScope() {
133  delete root_index_map_;
134  delete identity_map_;
135  isolate_->handle_scope_data()->canonical_scope = prev_canonical_scope_;
136}
137
138
139Object** CanonicalHandleScope::Lookup(Object* object) {
140  DCHECK_LE(canonical_level_, isolate_->handle_scope_data()->level);
141  if (isolate_->handle_scope_data()->level != canonical_level_) {
142    // We are in an inner handle scope. Do not canonicalize since we will leave
143    // this handle scope while still being in the canonical scope.
144    return HandleScope::CreateHandle(isolate_, object);
145  }
146  if (object->IsHeapObject()) {
147    int index = root_index_map_->Lookup(HeapObject::cast(object));
148    if (index != RootIndexMap::kInvalidRootIndex) {
149      return isolate_->heap()
150          ->root_handle(static_cast<Heap::RootListIndex>(index))
151          .location();
152    }
153  }
154  Object*** entry = identity_map_->Get(object);
155  if (*entry == nullptr) {
156    // Allocate new handle location.
157    *entry = HandleScope::CreateHandle(isolate_, object);
158  }
159  return reinterpret_cast<Object**>(*entry);
160}
161
162
163DeferredHandleScope::DeferredHandleScope(Isolate* isolate)
164    : impl_(isolate->handle_scope_implementer()) {
165  impl_->BeginDeferredScope();
166  HandleScopeData* data = impl_->isolate()->handle_scope_data();
167  Object** new_next = impl_->GetSpareOrNewBlock();
168  Object** new_limit = &new_next[kHandleBlockSize];
169  DCHECK(data->limit == &impl_->blocks()->last()[kHandleBlockSize]);
170  impl_->blocks()->Add(new_next);
171
172#ifdef DEBUG
173  prev_level_ = data->level;
174#endif
175  data->level++;
176  prev_limit_ = data->limit;
177  prev_next_ = data->next;
178  data->next = new_next;
179  data->limit = new_limit;
180}
181
182
183DeferredHandleScope::~DeferredHandleScope() {
184  impl_->isolate()->handle_scope_data()->level--;
185  DCHECK(handles_detached_);
186  DCHECK(impl_->isolate()->handle_scope_data()->level == prev_level_);
187}
188
189
190DeferredHandles* DeferredHandleScope::Detach() {
191  DeferredHandles* deferred = impl_->Detach(prev_limit_);
192  HandleScopeData* data = impl_->isolate()->handle_scope_data();
193  data->next = prev_next_;
194  data->limit = prev_limit_;
195#ifdef DEBUG
196  handles_detached_ = true;
197#endif
198  return deferred;
199}
200
201}  // namespace internal
202}  // namespace v8
203