*/
class EXPORT HandleScope {
public:
- HandleScope() : previous_(current_), is_closed_(false) {
- current_.extensions = 0;
- }
+ HandleScope();
- ~HandleScope() {
- // TODO(1245391): In a perfect world, there would be a way of not
- // having to check for explicitly closed scopes maybe through
- // subclassing HandleScope?
- if (!is_closed_) RestorePreviousState();
- }
+ ~HandleScope();
/**
- * TODO(1245391): Consider introducing a subclass for this.
* Closes the handle scope and returns the value as a handle in the
* previous scope, which is the new current scope after the call.
*/
void* operator new(size_t size);
void operator delete(void*, size_t);
+ // This Data class is accessible internally through a typedef in the
+ // ImplementationUtilities class.
class EXPORT Data {
public:
int extensions;
}
};
- static Data current_;
- const Data previous_;
-
- /**
- * Re-establishes the previous scope state. Should be called only
- * once, and only for the current scope.
- */
- void RestorePreviousState() {
- if (current_.extensions > 0) DeleteExtensions();
- current_ = previous_;
-#ifdef DEBUG
- ZapRange(current_.next, current_.limit);
-#endif
- }
+ Data previous_;
- // TODO(1245391): Consider creating a subclass for this.
+ // Allow for the active closing of HandleScopes which allows to pass a handle
+ // from the HandleScope being closed to the next top most HandleScope.
bool is_closed_;
void** RawClose(void** value);
- /** Deallocates any extensions used by the current scope.*/
- static void DeleteExtensions();
-
- // Zaps the handles in the half-open interval [start, end).
- static void ZapRange(void** start, void** end);
-
friend class ImplementationUtilities;
};
*/
static bool IsLocked();
+ /**
+ * Returns whether v8::Locker is being used by this V8 instance.
+ */
+ static bool IsActive() { return active_; }
+
private:
bool has_lock_;
bool top_level_;
+ static bool active_;
+
// Disallow copying and assigning.
Locker(const Locker&);
void operator=(const Locker&);
#include "platform.h"
#include "serialize.h"
#include "snapshot.h"
+#include "v8threads.h"
namespace i = v8::internal;
} while (false)
+#define API_ENTRY_CHECK(msg) \
+ do { \
+ if (v8::Locker::IsActive()) { \
+ ApiCheck(i::ThreadManager::IsLockedByCurrentThread(), \
+ msg, \
+ "Entering the V8 API without proper locking in place"); \
+ } \
+ } while (false)
+
// --- D a t a t h a t i s s p e c i f i c t o a t h r e a d ---
}
+ImplementationUtilities::HandleScopeData*
+ ImplementationUtilities::CurrentHandleScope() {
+ return &i::HandleScope::current_;
+}
+
+
+#ifdef DEBUG
+void ImplementationUtilities::ZapHandleRange(void** begin, void** end) {
+ i::HandleScope::ZapRange(begin, end);
+}
+#endif
+
+
v8::Handle<v8::Primitive> ImplementationUtilities::Undefined() {
if (IsDeadCheck("v8::Undefined()")) return v8::Handle<v8::Primitive>();
EnsureInitialized("v8::Undefined()");
// --- H a n d l e s ---
-HandleScope::Data HandleScope::current_ = { -1, NULL, NULL };
+HandleScope::HandleScope() : is_closed_(false) {
+ API_ENTRY_CHECK("HandleScope::HandleScope");
+ i::HandleScope::Enter(&previous_);
+}
-int HandleScope::NumberOfHandles() {
- int n = thread_local.Blocks()->length();
- if (n == 0) return 0;
- return ((n - 1) * i::kHandleBlockSize) +
- (current_.next - thread_local.Blocks()->last());
+HandleScope::~HandleScope() {
+ if (!is_closed_) {
+ i::HandleScope::Leave(&previous_);
+ }
}
-void** v8::HandleScope::CreateHandle(void* value) {
- void** result = current_.next;
- if (result == current_.limit) {
- // Make sure there's at least one scope on the stack and that the
- // top of the scope stack isn't a barrier.
- if (!ApiCheck(current_.extensions >= 0,
- "v8::HandleScope::CreateHandle()",
- "Cannot create a handle without a HandleScope")) {
- return NULL;
- }
- // If there's more room in the last block, we use that. This is used
- // for fast creation of scopes after scope barriers.
- if (!thread_local.Blocks()->is_empty()) {
- void** limit = &thread_local.Blocks()->last()[i::kHandleBlockSize];
- if (current_.limit != limit) {
- current_.limit = limit;
- }
- }
+int HandleScope::NumberOfHandles() {
+ return i::HandleScope::NumberOfHandles();
+}
- // If we still haven't found a slot for the handle, we extend the
- // current handle scope by allocating a new handle block.
- if (result == current_.limit) {
- // If there's a spare block, use it for growing the current scope.
- result = thread_local.GetSpareOrNewBlock();
- // Add the extension to the global list of blocks, but count the
- // extension as part of the current scope.
- thread_local.Blocks()->Add(result);
- current_.extensions++;
- current_.limit = &result[i::kHandleBlockSize];
- }
- }
- // Update the current next field, set the value in the created
- // handle, and return the result.
- ASSERT(result < current_.limit);
- current_.next = result + 1;
- *result = value;
- return result;
+void** v8::HandleScope::CreateHandle(void* value) {
+ return i::HandleScope::CreateHandle(value);
}
}
-void v8::HandleScope::DeleteExtensions() {
- ASSERT(current_.extensions != 0);
- thread_local.DeleteExtensions(current_.extensions);
-}
-
-
-void HandleScope::ZapRange(void** start, void** end) {
- if (start == NULL) return;
- for (void** p = start; p < end; p++) {
- *p = reinterpret_cast<void*>(v8::internal::kHandleZapValue);
- }
-}
-
-
void** v8::HandleScope::RawClose(void** value) {
if (!ApiCheck(!is_closed_,
"v8::HandleScope::Close()",
// Read the result before popping the handle block.
i::Object* result = reinterpret_cast<i::Object*>(*value);
is_closed_ = true;
- RestorePreviousState();
+ i::HandleScope::Leave(&previous_);
// Allocate a new handle on the previous handle block.
i::Handle<i::Object> handle(result);
char* HandleScopeImplementer::ArchiveThreadHelper(char* storage) {
- ImplementationUtilities::HandleScopeData* current =
- ImplementationUtilities::CurrentHandleScope();
+ v8::ImplementationUtilities::HandleScopeData* current =
+ v8::ImplementationUtilities::CurrentHandleScope();
handle_scope_data_ = *current;
memcpy(storage, this, sizeof(*this));
char* HandleScopeImplementer::RestoreThreadHelper(char* storage) {
memcpy(this, storage, sizeof(*this));
- *ImplementationUtilities::CurrentHandleScope() = handle_scope_data_;
+ *v8::ImplementationUtilities::CurrentHandleScope() = handle_scope_data_;
return storage + ArchiveSpacePerThread();
}
void HandleScopeImplementer::Iterate(
ObjectVisitor* v,
List<void**>* blocks,
- ImplementationUtilities::HandleScopeData* handle_data) {
+ v8::ImplementationUtilities::HandleScopeData* handle_data) {
// Iterate over all handles in the blocks except for the last.
for (int i = blocks->length() - 2; i >= 0; --i) {
Object** block =
void HandleScopeImplementer::Iterate(ObjectVisitor* v) {
- ImplementationUtilities::HandleScopeData* current =
- ImplementationUtilities::CurrentHandleScope();
+ v8::ImplementationUtilities::HandleScopeData* current =
+ v8::ImplementationUtilities::CurrentHandleScope();
Iterate(v, thread_local.Blocks(), current);
}
HandleScopeImplementer* thread_local =
reinterpret_cast<HandleScopeImplementer*>(storage);
List<void**>* blocks_of_archived_thread = thread_local->Blocks();
- ImplementationUtilities::HandleScopeData* handle_data_of_archived_thread =
+ v8::ImplementationUtilities::HandleScopeData* handle_data_of_archived_thread =
&thread_local->handle_scope_data_;
Iterate(v, blocks_of_archived_thread, handle_data_of_archived_thread);
#ifndef V8_API_H_
#define V8_API_H_
+#include "apiutils.h"
#include "factory.h"
namespace v8 {
};
-class ImplementationUtilities {
- public:
- static v8::Handle<v8::Primitive> Undefined();
- static v8::Handle<v8::Primitive> Null();
- static v8::Handle<v8::Boolean> True();
- static v8::Handle<v8::Boolean> False();
-
- static int GetNameCount(ExtensionConfiguration* that) {
- return that->name_count_;
- }
-
- static const char** GetNames(ExtensionConfiguration* that) {
- return that->names_;
- }
-
- static v8::Arguments NewArguments(Local<Value> data,
- Local<Object> holder,
- Local<Function> callee,
- bool is_construct_call,
- void** argv, int argc) {
- return v8::Arguments(data, holder, callee, is_construct_call, argv, argc);
- }
-
- // Introduce an alias for the handle scope data to allow non-friends
- // to access the HandleScope data.
- typedef v8::HandleScope::Data HandleScopeData;
-
- static HandleScopeData* CurrentHandleScope() {
- return &v8::HandleScope::current_;
- }
-
-#ifdef DEBUG
- static void ZapHandleRange(void** begin, void** end) {
- v8::HandleScope::ZapRange(begin, end);
- }
-#endif
-};
-
-
class Utils {
public:
static bool ReportApiFailure(const char* location, const char* message);
template <class T>
v8::internal::Handle<T> v8::internal::Handle<T>::EscapeFrom(
- HandleScope* scope) {
+ v8::HandleScope* scope) {
return Utils::OpenHandle(*scope->Close(Utils::ToLocal(*this)));
}
List<Handle<Object> > saved_contexts_;
bool ignore_out_of_memory;
// This is only used for threading support.
- ImplementationUtilities::HandleScopeData handle_scope_data_;
+ v8::ImplementationUtilities::HandleScopeData handle_scope_data_;
static void Iterate(ObjectVisitor* v,
- List<void**>* blocks,
- ImplementationUtilities::HandleScopeData* handle_data);
+ List<void**>* blocks,
+ v8::ImplementationUtilities::HandleScopeData* handle_data);
char* RestoreThreadHelper(char* from);
char* ArchiveThreadHelper(char* to);
for (int i = extensions; i > 1; --i) {
void** block = blocks.RemoveLast();
#ifdef DEBUG
- ImplementationUtilities::ZapHandleRange(block, &block[kHandleBlockSize]);
+ v8::ImplementationUtilities::ZapHandleRange(block,
+ &block[kHandleBlockSize]);
#endif
DeleteArray(block);
}
spare = reinterpret_cast<Object**>(blocks.RemoveLast());
#ifdef DEBUG
- ImplementationUtilities::ZapHandleRange(
+ v8::ImplementationUtilities::ZapHandleRange(
reinterpret_cast<void**>(spare),
reinterpret_cast<void**>(&spare[kHandleBlockSize]));
#endif
--- /dev/null
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_APIUTILS_H_
+#define V8_APIUTILS_H_
+
+namespace v8 {
+
+class ImplementationUtilities {
+ public:
+ static v8::Handle<v8::Primitive> Undefined();
+ static v8::Handle<v8::Primitive> Null();
+ static v8::Handle<v8::Boolean> True();
+ static v8::Handle<v8::Boolean> False();
+
+ static int GetNameCount(ExtensionConfiguration* that) {
+ return that->name_count_;
+ }
+
+ static const char** GetNames(ExtensionConfiguration* that) {
+ return that->names_;
+ }
+
+ static v8::Arguments NewArguments(Local<Value> data,
+ Local<Object> holder,
+ Local<Function> callee,
+ bool is_construct_call,
+ void** argv, int argc) {
+ return v8::Arguments(data, holder, callee, is_construct_call, argv, argc);
+ }
+
+ // Introduce an alias for the handle scope data to allow non-friends
+ // to access the HandleScope data.
+ typedef v8::HandleScope::Data HandleScopeData;
+
+ static HandleScopeData* CurrentHandleScope();
+
+#ifdef DEBUG
+ static void ZapHandleRange(void** begin, void** end);
+#endif
+};
+
+} // namespace v8
+
+#endif // V8_APIUTILS_H_
Handle<Object> Factory::NewError(const char* maker, const char* type,
Vector< Handle<Object> > args) {
- HandleScope scope;
+ v8::HandleScope scope; // Instantiate a closeable HandleScope for EscapeFrom.
Handle<FixedArray> array = Factory::NewFixedArray(args.length());
for (int i = 0; i < args.length(); i++) {
array->set(i, *args[i]);
#ifndef V8_HANDLES_INL_H_
#define V8_HANDLES_INL_H_
+#include "apiutils.h"
#include "handles.h"
#include "api.h"
#ifdef DEBUG
inline NoHandleAllocation::NoHandleAllocation() {
- ImplementationUtilities::HandleScopeData* current =
- ImplementationUtilities::CurrentHandleScope();
+ v8::ImplementationUtilities::HandleScopeData* current =
+ v8::ImplementationUtilities::CurrentHandleScope();
extensions_ = current->extensions;
// Shrink the current handle scope to make it impossible to do
// handle allocations without an explicit handle scope.
inline NoHandleAllocation::~NoHandleAllocation() {
// Restore state in current handle scope to re-enable handle
// allocations.
- ImplementationUtilities::CurrentHandleScope()->extensions = extensions_;
+ v8::ImplementationUtilities::CurrentHandleScope()->extensions = extensions_;
}
#endif
namespace v8 { namespace internal {
+v8::ImplementationUtilities::HandleScopeData HandleScope::current_ =
+ { -1, NULL, NULL };
+
+
+int HandleScope::NumberOfHandles() {
+ int n = HandleScopeImplementer::instance()->Blocks()->length();
+ if (n == 0) return 0;
+ return ((n - 1) * kHandleBlockSize) +
+ (current_.next - HandleScopeImplementer::instance()->Blocks()->last());
+}
+
+
+void** HandleScope::CreateHandle(void* value) {
+ void** result = current_.next;
+ if (result == current_.limit) {
+ // Make sure there's at least one scope on the stack and that the
+ // top of the scope stack isn't a barrier.
+ if (current_.extensions < 0) {
+ Utils::ReportApiFailure("v8::HandleScope::CreateHandle()",
+ "Cannot create a handle without a HandleScope");
+ return NULL;
+ }
+ HandleScopeImplementer* impl = HandleScopeImplementer::instance();
+ // If there's more room in the last block, we use that. This is used
+ // for fast creation of scopes after scope barriers.
+ if (!impl->Blocks()->is_empty()) {
+ void** limit = &impl->Blocks()->last()[kHandleBlockSize];
+ if (current_.limit != limit) {
+ current_.limit = limit;
+ }
+ }
+
+ // If we still haven't found a slot for the handle, we extend the
+ // current handle scope by allocating a new handle block.
+ if (result == current_.limit) {
+ // If there's a spare block, use it for growing the current scope.
+ result = impl->GetSpareOrNewBlock();
+ // Add the extension to the global list of blocks, but count the
+ // extension as part of the current scope.
+ impl->Blocks()->Add(result);
+ current_.extensions++;
+ current_.limit = &result[kHandleBlockSize];
+ }
+ }
+
+ // Update the current next field, set the value in the created
+ // handle, and return the result.
+ ASSERT(result < current_.limit);
+ current_.next = result + 1;
+ *result = value;
+ return result;
+}
+
+
+void HandleScope::DeleteExtensions() {
+ ASSERT(current_.extensions != 0);
+ HandleScopeImplementer::instance()->DeleteExtensions(current_.extensions);
+}
+
+
+void HandleScope::ZapRange(void** start, void** end) {
+ if (start == NULL) return;
+ for (void** p = start; p < end; p++) {
+ *p = reinterpret_cast<void*>(v8::internal::kHandleZapValue);
+ }
+}
+
+
Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content,
Handle<JSArray> array) {
CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray);
#ifndef V8_HANDLES_H_
#define V8_HANDLES_H_
+#include "apiutils.h"
+
namespace v8 { namespace internal {
// ----------------------------------------------------------------------------
// A Handle provides a reference to an object that survives relocation by
// the garbage collector.
-// Handles are only valid withing a HandleScope.
+// Handles are only valid within a HandleScope.
// When a handle is created for an object a cell is allocated in the heap.
template<class T>
};
+// 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
+// deleted or another handle scope is created. If there is already a
+// handle scope and a new one is created, all allocations will take
+// place in the new handle scope until it is deleted. After that,
+// new handles will again be allocated in the original handle scope.
+//
+// After the handle scope of a local handle has been deleted the
+// garbage collector will no longer track the object stored in the
+// handle and may deallocate it. The behavior of accessing a handle
+// for which the handle scope has been deleted is undefined.
+class HandleScope {
+ public:
+ HandleScope() : previous_(current_) {
+ current_.extensions = 0;
+ }
+
+ ~HandleScope() {
+ Leave(&previous_);
+ }
+
+ // Counts the number of allocated handles.
+ static int NumberOfHandles();
+
+ // Creates a new handle with the given value.
+ static void** CreateHandle(void* value);
+
+ private:
+ // Prevent heap allocation or illegal handle scopes.
+ HandleScope(const HandleScope&);
+ void operator=(const HandleScope&);
+ void* operator new(size_t size);
+ void operator delete(void* size_t);
+
+ static v8::ImplementationUtilities::HandleScopeData current_;
+ const v8::ImplementationUtilities::HandleScopeData previous_;
+
+ // Pushes a fresh handle scope to be used when allocating new handles.
+ static void Enter(
+ v8::ImplementationUtilities::HandleScopeData* previous) {
+ *previous = current_;
+ current_.extensions = 0;
+ }
+
+ // Re-establishes the previous scope state. Should be called only
+ // once, and only for the current scope.
+ static void Leave(
+ const v8::ImplementationUtilities::HandleScopeData* previous) {
+ if (current_.extensions > 0) {
+ DeleteExtensions();
+ }
+ current_ = *previous;
+#ifdef DEBUG
+ ZapRange(current_.next, current_.limit);
+#endif
+ }
+
+ // Deallocates any extensions used by the current scope.
+ static void DeleteExtensions();
+
+ // Zaps the handles in the half-open interval [start, end).
+ static void ZapRange(void** start, void** end);
+
+ friend class v8::HandleScope;
+ friend class v8::ImplementationUtilities;
+};
+
+
// ----------------------------------------------------------------------------
// Handle operations.
// They might invoke garbage collection. The result is an handle to
Vector< Handle<Object> > args,
Handle<String> stack_trace) {
// Build error message object
- HandleScope scope;
+ v8::HandleScope scope; // Instantiate a closeable HandleScope for EscapeFrom.
Handle<Object> type_str = Factory::LookupAsciiSymbol(type);
Handle<Object> array = Factory::NewJSArray(args.length());
for (int i = 0; i < args.length(); i++)
static internal::Thread::LocalStorageKey thread_state_key =
internal::Thread::CreateThreadLocalKey();
+
+// Track whether this V8 instance has ever called v8::Locker. This allows the
+// API code to verify that the lock is always held when V8 is being entered.
+bool Locker::active_ = false;
+
+
// Constructor for the Locker object. Once the Locker is constructed the
// current thread will be guaranteed to have the big V8 lock.
Locker::Locker() : has_lock_(false), top_level_(true) {
+ // Record that the Locker has been used at least once.
+ active_ = true;
// Get the big lock if necessary.
if (!internal::ThreadManager::IsLockedByCurrentThread()) {
internal::ThreadManager::Lock();
/* Begin PBXFileReference section */
8900116B0E71CA2300F91F35 /* libraries.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = libraries.cc; sourceTree = "<group>"; };
+ 893986D40F29020C007D5254 /* apiutils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = apiutils.h; sourceTree = "<group>"; };
8944AD0E0F1D4D3A0028D560 /* regexp-stack.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "regexp-stack.cc"; sourceTree = "<group>"; };
8944AD0F0F1D4D3A0028D560 /* regexp-stack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "regexp-stack.h"; sourceTree = "<group>"; };
89471C7F0EB23EE400B6874B /* flag-definitions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "flag-definitions.h"; sourceTree = "<group>"; };
897FF0F90E719B8F00D62E90 /* allocation.h */,
897FF0FA0E719B8F00D62E90 /* api.cc */,
897FF0FB0E719B8F00D62E90 /* api.h */,
+ 893986D40F29020C007D5254 /* apiutils.h */,
897FF0FC0E719B8F00D62E90 /* arguments.h */,
897FF0FD0E719B8F00D62E90 /* assembler-arm-inl.h */,
897FF0FE0E719B8F00D62E90 /* assembler-arm.cc */,