// Copyright 2008 Google Inc. 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_API_H_ #define V8_API_H_ #include "factory.h" namespace v8 { // Constants used in the implementation of the API. The most natural thing // would usually be to place these with the classes that use them, but // we want to keep them out of v8.h because it is an externally // visible file. class Consts { public: enum TemplateType { FUNCTION_TEMPLATE = 0, OBJECT_TEMPLATE = 1 }; }; // Utilities for working with neander-objects, primitive // env-independent JSObjects used by the api. class NeanderObject { public: explicit NeanderObject(int size); inline NeanderObject(v8::internal::Handle obj); inline NeanderObject(v8::internal::Object* obj); inline v8::internal::Object* get(int index); inline void set(int index, v8::internal::Object* value); inline v8::internal::Handle value() { return value_; } int size(); private: v8::internal::Handle value_; }; // Utilities for working with neander-arrays, a simple extensible // array abstraction built on neander-objects. class NeanderArray { public: NeanderArray(); inline NeanderArray(v8::internal::Handle obj); inline v8::internal::Handle value() { return obj_.value(); } void add(v8::internal::Handle value); int length(); v8::internal::Object* get(int index); // Change the value at an index to undefined value. If the index is // out of bounds, the request is ignored. Returns the old value. void set(int index, v8::internal::Object* value); private: NeanderObject obj_; }; NeanderObject::NeanderObject(v8::internal::Handle obj) : value_(v8::internal::Handle::cast(obj)) { } NeanderObject::NeanderObject(v8::internal::Object* obj) : value_(v8::internal::Handle( v8::internal::JSObject::cast(obj))) { } NeanderArray::NeanderArray(v8::internal::Handle obj) : obj_(obj) { } v8::internal::Object* NeanderObject::get(int offset) { ASSERT(value()->HasFastElements()); return v8::internal::FixedArray::cast(value()->elements())->get(offset); } void NeanderObject::set(int offset, v8::internal::Object* value) { ASSERT(value_->HasFastElements()); v8::internal::FixedArray::cast(value_->elements())->set(offset, value); } template static inline T ToCData(v8::internal::Object* obj) { STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address)); return reinterpret_cast( reinterpret_cast(v8::internal::Proxy::cast(obj)->proxy())); } template static inline v8::internal::Handle FromCData(T obj) { STATIC_ASSERT(sizeof(T) == sizeof(v8::internal::Address)); return v8::internal::Factory::NewProxy( reinterpret_cast(reinterpret_cast(obj))); } v8::Arguments::Arguments(v8::Local data, v8::Local holder, v8::Local callee, bool is_construct_call, void** values, int length) : data_(data), holder_(holder), callee_(callee), is_construct_call_(is_construct_call), values_(values), length_(length) { } enum ExtensionTraversalState { UNVISITED, VISITED, INSTALLED }; class RegisteredExtension { public: explicit RegisteredExtension(Extension* extension); static void Register(RegisteredExtension* that); Extension* extension() { return extension_; } RegisteredExtension* next() { return next_; } RegisteredExtension* next_auto() { return next_auto_; } ExtensionTraversalState state() { return state_; } void set_state(ExtensionTraversalState value) { state_ = value; } static RegisteredExtension* first_extension() { return first_extension_; } private: Extension* extension_; RegisteredExtension* next_; RegisteredExtension* next_auto_; ExtensionTraversalState state_; static RegisteredExtension* first_extension_; static RegisteredExtension* first_auto_extension_; }; class ImplementationUtilities { public: static v8::Handle Undefined(); static v8::Handle Null(); static v8::Handle True(); static v8::Handle False(); static int GetNameCount(ExtensionConfiguration* that) { return that->name_count_; } static const char** GetNames(ExtensionConfiguration* that) { return that->names_; } static v8::Arguments NewArguments(Local data, Local holder, Local 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); static Local ToFunctionTemplate(NeanderObject obj); static Local ToObjectTemplate(NeanderObject obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local MessageToLocal( v8::internal::Handle obj); static inline Local NumberToLocal( v8::internal::Handle obj); static inline Local IntegerToLocal( v8::internal::Handle obj); static inline Local Uint32ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline Local ToLocal( v8::internal::Handle obj); static inline v8::internal::Handle OpenHandle(Template* that); static inline v8::internal::Handle OpenHandle(FunctionTemplate* that); static inline v8::internal::Handle OpenHandle(ObjectTemplate* that); static inline v8::internal::Handle OpenHandle(Data* data); static inline v8::internal::Handle OpenHandle(v8::Object* data); static inline v8::internal::Handle OpenHandle(v8::Array* data); static inline v8::internal::Handle OpenHandle(String* data); static inline v8::internal::Handle OpenHandle(Script* data); static inline v8::internal::Handle OpenHandle(Function* data); static inline v8::internal::Handle OpenHandle(Message* message); static inline v8::internal::Handle OpenHandle(v8::Context* context); static inline v8::internal::Handle OpenHandle(v8::Signature* sig); static inline v8::internal::Handle OpenHandle(v8::TypeSwitch* that); }; template static inline T* ToApi(v8::internal::Handle obj) { return reinterpret_cast(obj.location()); } template v8::internal::Handle v8::internal::Handle::EscapeFrom( HandleScope* scope) { return Utils::OpenHandle(*scope->Close(Utils::ToLocal(*this))); } // Implementations of ToLocal #define MAKE_TO_LOCAL(Name, From, To) \ Local Utils::Name(v8::internal::Handle obj) { \ return Local(reinterpret_cast(obj.location())); \ } MAKE_TO_LOCAL(ToLocal, Context, Context) MAKE_TO_LOCAL(ToLocal, Object, Value) MAKE_TO_LOCAL(ToLocal, JSFunction, Function) MAKE_TO_LOCAL(ToLocal, String, String) MAKE_TO_LOCAL(ToLocal, JSObject, Object) MAKE_TO_LOCAL(ToLocal, JSArray, Array) MAKE_TO_LOCAL(ToLocal, Proxy, External) MAKE_TO_LOCAL(ToLocal, FunctionTemplateInfo, FunctionTemplate) MAKE_TO_LOCAL(ToLocal, ObjectTemplateInfo, ObjectTemplate) MAKE_TO_LOCAL(ToLocal, SignatureInfo, Signature) MAKE_TO_LOCAL(ToLocal, TypeSwitchInfo, TypeSwitch) MAKE_TO_LOCAL(MessageToLocal, Object, Message) MAKE_TO_LOCAL(NumberToLocal, Object, Number) MAKE_TO_LOCAL(IntegerToLocal, Object, Integer) MAKE_TO_LOCAL(Uint32ToLocal, Object, Uint32) #undef MAKE_TO_LOCAL // Implementations of OpenHandle #define MAKE_OPEN_HANDLE(From, To) \ v8::internal::Handle Utils::OpenHandle(v8::From* that) { \ return v8::internal::Handle( \ reinterpret_cast(that)); \ } MAKE_OPEN_HANDLE(Template, TemplateInfo) MAKE_OPEN_HANDLE(FunctionTemplate, FunctionTemplateInfo) MAKE_OPEN_HANDLE(ObjectTemplate, ObjectTemplateInfo) MAKE_OPEN_HANDLE(Signature, SignatureInfo) MAKE_OPEN_HANDLE(TypeSwitch, TypeSwitchInfo) MAKE_OPEN_HANDLE(Data, Object) MAKE_OPEN_HANDLE(Object, JSObject) MAKE_OPEN_HANDLE(Array, JSArray) MAKE_OPEN_HANDLE(String, String) MAKE_OPEN_HANDLE(Script, JSFunction) MAKE_OPEN_HANDLE(Function, JSFunction) MAKE_OPEN_HANDLE(Message, JSObject) MAKE_OPEN_HANDLE(Context, Context) #undef MAKE_OPEN_HANDLE namespace internal { // 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 external implementation details in // our public header file, which is undesirable. // // There is a singleton instance of this class to hold the per-thread data. // For multithreaded V8 programs this data is copied in and out of storage // so that the currently executing thread always has its own copy of this // data. class HandleScopeImplementer { public: HandleScopeImplementer() : blocks(0), entered_contexts_(0), saved_contexts_(0), saved_security_contexts_(0) { Initialize(); } void Initialize() { blocks.Initialize(0); entered_contexts_.Initialize(0); saved_contexts_.Initialize(0); saved_security_contexts_.Initialize(0); spare = NULL; ignore_out_of_memory = false; call_depth = 0; } static HandleScopeImplementer* instance(); // Threading support for handle data. static int ArchiveSpacePerThread(); static char* RestoreThread(char* from); static char* ArchiveThread(char* to); // Garbage collection support. static void Iterate(v8::internal::ObjectVisitor* v); static char* Iterate(v8::internal::ObjectVisitor* v, char* data); inline void** GetSpareOrNewBlock(); inline void DeleteExtensions(int extensions); inline void IncrementCallDepth() {call_depth++;} inline void DecrementCallDepth() {call_depth--;} inline bool CallDepthIsZero() { return call_depth == 0; } inline void EnterContext(Handle context); inline bool LeaveLastContext(); // Returns the last entered context or an empty handle if no // contexts have been entered. inline Handle LastEnteredContext(); inline void SaveContext(Handle context); inline Handle RestoreContext(); inline bool HasSavedContexts(); inline void SaveSecurityContext(Handle context); inline Handle RestoreSecurityContext(); inline bool HasSavedSecurityContexts(); inline List* Blocks() { return &blocks; } inline bool IgnoreOutOfMemory() { return ignore_out_of_memory; } inline void SetIgnoreOutOfMemory(bool value) { ignore_out_of_memory = value; } private: List blocks; Object** spare; int call_depth; // Used as a stack to keep track of entered contexts. List > entered_contexts_; // Used as a stack to keep track of saved contexts. List > saved_contexts_; // Used as a stack to keep track of saved security contexts. List > saved_security_contexts_; bool ignore_out_of_memory; // This is only used for threading support. ImplementationUtilities::HandleScopeData handle_scope_data_; static void Iterate(ObjectVisitor* v, List* blocks, ImplementationUtilities::HandleScopeData* handle_data); char* RestoreThreadHelper(char* from); char* ArchiveThreadHelper(char* to); DISALLOW_COPY_AND_ASSIGN(HandleScopeImplementer); }; static const int kHandleBlockSize = v8::internal::KB - 2; // fit in one page void HandleScopeImplementer::SaveContext(Handle context) { saved_contexts_.Add(context); } Handle HandleScopeImplementer::RestoreContext() { return saved_contexts_.RemoveLast(); } bool HandleScopeImplementer::HasSavedContexts() { return !saved_contexts_.is_empty(); } void HandleScopeImplementer::SaveSecurityContext(Handle context) { saved_security_contexts_.Add(context); } Handle HandleScopeImplementer::RestoreSecurityContext() { return saved_security_contexts_.RemoveLast(); } bool HandleScopeImplementer::HasSavedSecurityContexts() { return !saved_security_contexts_.is_empty(); } void HandleScopeImplementer::EnterContext(Handle context) { entered_contexts_.Add(context); } bool HandleScopeImplementer::LeaveLastContext() { if (entered_contexts_.is_empty()) return false; entered_contexts_.RemoveLast(); return true; } Handle HandleScopeImplementer::LastEnteredContext() { if (entered_contexts_.is_empty()) return Handle::null(); return entered_contexts_.last(); } // If there's a spare block, use it for growing the current scope. void** HandleScopeImplementer::GetSpareOrNewBlock() { void** block = (spare != NULL) ? reinterpret_cast(spare) : NewArray(kHandleBlockSize); spare = NULL; return block; } void HandleScopeImplementer::DeleteExtensions(int extensions) { if (spare != NULL) { DeleteArray(spare); spare = NULL; } for (int i = extensions; i > 1; --i) { void** block = blocks.RemoveLast(); #ifdef DEBUG ImplementationUtilities::ZapHandleRange(block, &block[kHandleBlockSize]); #endif DeleteArray(block); } spare = reinterpret_cast(blocks.RemoveLast()); #ifdef DEBUG ImplementationUtilities::ZapHandleRange( reinterpret_cast(spare), reinterpret_cast(&spare[kHandleBlockSize])); #endif } } } // namespace v8::internal #endif // V8_API_H_