void HandleScopeImplementer::IterateThis(ObjectVisitor* v) {
+#ifdef DEBUG
+ bool found_block_before_deferred = false;
+#endif
// Iterate over all handles in the blocks except for the last.
for (int i = blocks()->length() - 2; i >= 0; --i) {
Object** block = blocks()->at(i);
- v->VisitPointers(block, &block[kHandleBlockSize]);
+ if (last_handle_before_deferred_block_ != NULL &&
+ (last_handle_before_deferred_block_ < &block[kHandleBlockSize]) &&
+ (last_handle_before_deferred_block_ >= block)) {
+ v->VisitPointers(block, last_handle_before_deferred_block_);
+ ASSERT(!found_block_before_deferred);
+#ifdef DEBUG
+ found_block_before_deferred = true;
+#endif
+ } else {
+ v->VisitPointers(block, &block[kHandleBlockSize]);
+ }
}
+ ASSERT(last_handle_before_deferred_block_ == NULL ||
+ found_block_before_deferred);
+
// Iterate over live handles in the last block (if any).
if (!blocks()->is_empty()) {
v->VisitPointers(blocks()->last(), handle_scope_data_.next);
Object** start = reinterpret_cast<Object**>(&saved_contexts_.first());
v->VisitPointers(start, start + saved_contexts_.length());
}
+
+ for (DeferredHandles* deferred = deferred_handles_head_;
+ deferred != NULL;
+ deferred = deferred->next_) {
+ deferred->Iterate(v);
+ }
}
return storage + ArchiveSpacePerThread();
}
+
+DeferredHandles* HandleScopeImplementer::Detach(Object** prev_limit) {
+ DeferredHandles* deferred = new DeferredHandles(
+ deferred_handles_head_, isolate()->handle_scope_data()->next, this);
+
+ while (!blocks_.is_empty()) {
+ Object** block_start = blocks_.last();
+ Object** block_limit = &block_start[kHandleBlockSize];
+ // We should not need to check for NoHandleAllocation here. Assert
+ // this.
+ ASSERT(prev_limit == block_limit ||
+ !(block_start <= prev_limit && prev_limit <= block_limit));
+ if (prev_limit == block_limit) break;
+ deferred->blocks_.Add(blocks_.last());
+ blocks_.RemoveLast();
+ }
+
+ ASSERT(!blocks_.is_empty() && prev_limit != NULL);
+ deferred_handles_head_ = deferred;
+ ASSERT(last_handle_before_deferred_block_ != NULL);
+ last_handle_before_deferred_block_ = NULL;
+ return deferred;
+}
+
+
+void HandleScopeImplementer::DestroyDeferredHandles(DeferredHandles* deferred) {
+ if (deferred_handles_head_ == deferred) {
+ deferred_handles_head_ = deferred_handles_head_->next_;
+ }
+ if (deferred->next_ != NULL) {
+ deferred->next_->previous_ = deferred->previous_;
+ }
+ if (deferred->previous_ != NULL) {
+ deferred->previous_->next_ = deferred->next_;
+ }
+ for (int i = 0; i < deferred->blocks_.length(); i++) {
+#ifdef DEBUG
+ HandleScope::ZapRange(deferred->blocks_[i],
+ &deferred->blocks_[i][kHandleBlockSize]);
+#endif
+ if (spare_ != NULL) DeleteArray(spare_);
+ spare_ = deferred->blocks_[i];
+ }
+}
+
+
+void HandleScopeImplementer::BeginDeferredScope() {
+ ASSERT(last_handle_before_deferred_block_ == NULL);
+ last_handle_before_deferred_block_ = isolate()->handle_scope_data()->next;
+}
+
+
+DeferredHandles::~DeferredHandles() {
+ impl_->DestroyDeferredHandles(this);
+}
+
+
+void DeferredHandles::Iterate(ObjectVisitor* v) {
+ ASSERT(!blocks_.is_empty());
+
+ for (int i = 0; i < (blocks_.length() - 1); i++) {
+ v->VisitPointers(blocks_[i], &blocks_[i][kHandleBlockSize]);
+ }
+
+ ASSERT((last_block_limit_ >= blocks_.last()) &&
+ (last_block_limit_ < &(blocks_.last())[kHandleBlockSize]));
+
+ v->VisitPointers(blocks_.last(), last_block_limit_);
+}
+
+
} } // namespace v8::internal
};
+class DeferredHandles {
+ public:
+ ~DeferredHandles();
+
+ private:
+ DeferredHandles(DeferredHandles* next, Object** last_block_limit,
+ HandleScopeImplementer* impl)
+ : next_(next), previous_(NULL), last_block_limit_(last_block_limit),
+ impl_(impl) {}
+
+ void Iterate(ObjectVisitor* v);
+
+ List<Object**> blocks_;
+ DeferredHandles* next_;
+ DeferredHandles* previous_;
+ Object** last_block_limit_;
+ HandleScopeImplementer* impl_;
+
+ friend class HandleScopeImplementer;
+};
+
+
// This class is here in order to be able to declare it a friend of
// HandleScope. Moving these methods to be members of HandleScope would be
// neat in some ways, but it would expose internal implementation details in
entered_contexts_(0),
saved_contexts_(0),
spare_(NULL),
- call_depth_(0) { }
+ call_depth_(0),
+ last_handle_before_deferred_block_(NULL),
+ deferred_handles_head_(NULL) { }
~HandleScopeImplementer() {
DeleteArray(spare_);
inline bool HasSavedContexts();
inline List<internal::Object**>* blocks() { return &blocks_; }
+ Isolate* isolate() const { return isolate_; }
private:
void ResetAfterArchive() {
ASSERT(call_depth_ == 0);
}
+ void BeginDeferredScope();
+ DeferredHandles* Detach(Object** prev_limit);
+ void DestroyDeferredHandles(DeferredHandles* handles);
+
Isolate* isolate_;
List<internal::Object**> blocks_;
// Used as a stack to keep track of entered contexts.
List<Context*> saved_contexts_;
Object** spare_;
int call_depth_;
+ Object** last_handle_before_deferred_block_;
+ DeferredHandles* deferred_handles_head_;
// This is only used for threading support.
v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
char* RestoreThreadHelper(char* from);
char* ArchiveThreadHelper(char* to);
+ friend class DeferredHandles;
+ friend class DeferredHandleScope;
+
DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer);
};
extension_(NULL),
pre_parse_data_(NULL),
osr_ast_id_(AstNode::kNoNumber),
- zone_(zone) {
+ zone_(zone),
+ deferred_handles_(NULL) {
Initialize(BASE);
}
extension_(NULL),
pre_parse_data_(NULL),
osr_ast_id_(AstNode::kNoNumber),
- zone_(zone) {
+ zone_(zone),
+ deferred_handles_(NULL) {
Initialize(BASE);
}
extension_(NULL),
pre_parse_data_(NULL),
osr_ast_id_(AstNode::kNoNumber),
- zone_(zone) {
+ zone_(zone),
+ deferred_handles_(NULL) {
Initialize(BASE);
}
+CompilationInfo::~CompilationInfo() {
+ delete deferred_handles_;
+}
+
+
// Disable optimization for the rest of the compilation pipeline.
void CompilationInfo::DisableOptimization() {
bool is_optimizable_closure =
CompilationInfo(Handle<SharedFunctionInfo> shared_info, Zone* zone);
CompilationInfo(Handle<JSFunction> closure, Zone* zone);
+ ~CompilationInfo();
+
Isolate* isolate() {
ASSERT(Isolate::Current() == isolate_);
return isolate_;
// current compilation pipeline.
void AbortOptimization();
+ void set_deferred_handles(DeferredHandles* deferred_handles) {
+ ASSERT(deferred_handles_ == NULL);
+ deferred_handles_ = deferred_handles;
+ }
+
private:
Isolate* isolate_;
// CompilationInfo allocates.
Zone* zone_;
+ DeferredHandles* deferred_handles_;
+
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};
};
+// A wrapper around a CompilationInfo that detaches the Handles from
+// the underlying DeferredHandleScope and stores them in info_ on
+// destruction.
+class CompilationHandleScope BASE_EMBEDDED {
+ public:
+ explicit CompilationHandleScope(CompilationInfo* info)
+ : deferred_(info->isolate()), info_(info) {}
+ ~CompilationHandleScope() {
+ info_->set_deferred_handles(deferred_.Detach());
+ }
+
+ private:
+ DeferredHandleScope deferred_;
+ CompilationInfo* info_;
+};
+
+
// The V8 compiler
//
// General strategy: Source code is translated into an anonymous function w/o
return len;
}
+
+DeferredHandleScope::DeferredHandleScope(Isolate* isolate)
+ : impl_(isolate->handle_scope_implementer()) {
+ impl_->BeginDeferredScope();
+ Object** new_next = impl_->GetSpareOrNewBlock();
+ Object** new_limit = &new_next[kHandleBlockSize];
+ impl_->blocks()->Add(new_next);
+
+ v8::ImplementationUtilities::HandleScopeData* data =
+ impl_->isolate()->handle_scope_data();
+#ifdef DEBUG
+ prev_level_ = data->level;
+#endif
+ data->level++;
+ prev_limit_ = data->limit;
+ prev_next_ = data->next;
+ data->next = new_next;
+ data->limit = new_limit;
+}
+
+
+DeferredHandleScope::~DeferredHandleScope() {
+ impl_->isolate()->handle_scope_data()->level--;
+ ASSERT(handles_detached_);
+ ASSERT(impl_->isolate()->handle_scope_data()->level == prev_level_);
+}
+
+
+DeferredHandles* DeferredHandleScope::Detach() {
+ DeferredHandles* deferred = impl_->Detach(prev_limit_);
+ v8::ImplementationUtilities::HandleScopeData* data =
+ impl_->isolate()->handle_scope_data();
+ data->next = prev_next_;
+ data->limit = prev_limit_;
+#ifdef DEBUG
+ handles_detached_ = true;
+#endif
+ return deferred;
+}
+
+
} } // namespace v8::internal
};
+class HandleScopeImplementer;
+
+
// A stack-allocated class that governs a number of local handles.
// After a handle scope has been created, all local handles will be
// allocated within that handle scope until either the handle scope is
static void ZapRange(internal::Object** start, internal::Object** end);
friend class v8::HandleScope;
+ friend class v8::internal::HandleScopeImplementer;
friend class v8::ImplementationUtilities;
};
+class DeferredHandles;
+
+
+class DeferredHandleScope {
+ public:
+ explicit DeferredHandleScope(Isolate* isolate);
+ // The DeferredHandles object returned stores the Handles created
+ // since the creation of this DeferredHandleScope. The Handles are
+ // alive as long as the DeferredHandles object is alive.
+ DeferredHandles* Detach();
+ ~DeferredHandleScope();
+
+ private:
+ Object** prev_limit_;
+ Object** prev_next_;
+ HandleScopeImplementer* impl_;
+
+#ifdef DEBUG
+ bool handles_detached_;
+ int prev_level_;
+#endif
+
+ friend class HandleScopeImplementer;
+};
+
+
// ----------------------------------------------------------------------------
// Handle operations.
// They might invoke garbage collection. The result is an handle to
{
HPhase phase("H_Block building");
+ CompilationHandleScope handle_scope(info());
current_block_ = graph()->entry_block();
Scope* scope = info()->scope();