// 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. #include "v8.h" #include "api.h" #include "arguments.h" #include "bootstrapper.h" #include "compiler.h" #include "debug.h" #include "execution.h" #include "global-handles.h" #include "heap-profiler.h" #include "messages.h" #include "platform.h" #include "profile-generator-inl.h" #include "serialize.h" #include "snapshot.h" #include "top.h" #include "utils.h" #include "v8threads.h" #include "version.h" #include "../include/v8-profiler.h" #define LOG_API(expr) LOG(ApiEntryCall(expr)) #ifdef ENABLE_VMSTATE_TRACKING #define ENTER_V8 i::VMState __state__(i::OTHER) #define LEAVE_V8 i::VMState __state__(i::EXTERNAL) #else #define ENTER_V8 ((void) 0) #define LEAVE_V8 ((void) 0) #endif namespace v8 { #define ON_BAILOUT(location, code) \ if (IsDeadCheck(location) || v8::V8::IsExecutionTerminating()) { \ code; \ UNREACHABLE(); \ } #define EXCEPTION_PREAMBLE() \ thread_local.IncrementCallDepth(); \ ASSERT(!i::Top::external_caught_exception()); \ bool has_pending_exception = false #define EXCEPTION_BAILOUT_CHECK(value) \ do { \ thread_local.DecrementCallDepth(); \ if (has_pending_exception) { \ if (thread_local.CallDepthIsZero() && i::Top::is_out_of_memory()) { \ if (!thread_local.ignore_out_of_memory()) \ i::V8::FatalProcessOutOfMemory(NULL); \ } \ bool call_depth_is_zero = thread_local.CallDepthIsZero(); \ i::Top::OptionalRescheduleException(call_depth_is_zero); \ return value; \ } \ } 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 --- static i::HandleScopeImplementer thread_local; // --- E x c e p t i o n B e h a v i o r --- static FatalErrorCallback exception_behavior = NULL; static void DefaultFatalErrorHandler(const char* location, const char* message) { ENTER_V8; API_Fatal(location, message); } static FatalErrorCallback& GetFatalErrorHandler() { if (exception_behavior == NULL) { exception_behavior = DefaultFatalErrorHandler; } return exception_behavior; } // When V8 cannot allocated memory FatalProcessOutOfMemory is called. // The default fatal error handler is called and execution is stopped. void i::V8::FatalProcessOutOfMemory(const char* location, bool take_snapshot) { i::HeapStats heap_stats; int start_marker; heap_stats.start_marker = &start_marker; int new_space_size; heap_stats.new_space_size = &new_space_size; int new_space_capacity; heap_stats.new_space_capacity = &new_space_capacity; int old_pointer_space_size; heap_stats.old_pointer_space_size = &old_pointer_space_size; int old_pointer_space_capacity; heap_stats.old_pointer_space_capacity = &old_pointer_space_capacity; int old_data_space_size; heap_stats.old_data_space_size = &old_data_space_size; int old_data_space_capacity; heap_stats.old_data_space_capacity = &old_data_space_capacity; int code_space_size; heap_stats.code_space_size = &code_space_size; int code_space_capacity; heap_stats.code_space_capacity = &code_space_capacity; int map_space_size; heap_stats.map_space_size = &map_space_size; int map_space_capacity; heap_stats.map_space_capacity = &map_space_capacity; int cell_space_size; heap_stats.cell_space_size = &cell_space_size; int cell_space_capacity; heap_stats.cell_space_capacity = &cell_space_capacity; int lo_space_size; heap_stats.lo_space_size = &lo_space_size; int global_handle_count; heap_stats.global_handle_count = &global_handle_count; int weak_global_handle_count; heap_stats.weak_global_handle_count = &weak_global_handle_count; int pending_global_handle_count; heap_stats.pending_global_handle_count = &pending_global_handle_count; int near_death_global_handle_count; heap_stats.near_death_global_handle_count = &near_death_global_handle_count; int destroyed_global_handle_count; heap_stats.destroyed_global_handle_count = &destroyed_global_handle_count; int memory_allocator_size; heap_stats.memory_allocator_size = &memory_allocator_size; int memory_allocator_capacity; heap_stats.memory_allocator_capacity = &memory_allocator_capacity; int objects_per_type[LAST_TYPE + 1] = {0}; heap_stats.objects_per_type = objects_per_type; int size_per_type[LAST_TYPE + 1] = {0}; heap_stats.size_per_type = size_per_type; int os_error; heap_stats.os_error = &os_error; int end_marker; heap_stats.end_marker = &end_marker; i::Heap::RecordStats(&heap_stats, take_snapshot); i::V8::SetFatalError(); FatalErrorCallback callback = GetFatalErrorHandler(); { LEAVE_V8; callback(location, "Allocation failed - process out of memory"); } // If the callback returns, we stop execution. UNREACHABLE(); } void V8::SetFatalErrorHandler(FatalErrorCallback that) { exception_behavior = that; } bool Utils::ReportApiFailure(const char* location, const char* message) { FatalErrorCallback callback = GetFatalErrorHandler(); callback(location, message); i::V8::SetFatalError(); return false; } bool V8::IsDead() { return i::V8::IsDead(); } static inline bool ApiCheck(bool condition, const char* location, const char* message) { return condition ? true : Utils::ReportApiFailure(location, message); } static bool ReportV8Dead(const char* location) { FatalErrorCallback callback = GetFatalErrorHandler(); callback(location, "V8 is no longer usable"); return true; } static bool ReportEmptyHandle(const char* location) { FatalErrorCallback callback = GetFatalErrorHandler(); callback(location, "Reading from empty handle"); return true; } /** * IsDeadCheck checks that the vm is usable. If, for instance, the vm has been * out of memory at some point this check will fail. It should be called on * entry to all methods that touch anything in the heap, except destructors * which you sometimes can't avoid calling after the vm has crashed. Functions * that call EnsureInitialized or ON_BAILOUT don't have to also call * IsDeadCheck. ON_BAILOUT has the advantage over EnsureInitialized that you * can arrange to return if the VM is dead. This is needed to ensure that no VM * heap allocations are attempted on a dead VM. EnsureInitialized has the * advantage over ON_BAILOUT that it actually initializes the VM if this has not * yet been done. */ static inline bool IsDeadCheck(const char* location) { return !i::V8::IsRunning() && i::V8::IsDead() ? ReportV8Dead(location) : false; } static inline bool EmptyCheck(const char* location, v8::Handle obj) { return obj.IsEmpty() ? ReportEmptyHandle(location) : false; } static inline bool EmptyCheck(const char* location, const v8::Data* obj) { return (obj == 0) ? ReportEmptyHandle(location) : false; } // --- S t a t i c s --- static i::StringInputBuffer write_input_buffer; static inline bool EnsureInitialized(const char* location) { if (i::V8::IsRunning()) { return true; } if (IsDeadCheck(location)) { return false; } return ApiCheck(v8::V8::Initialize(), location, "Error initializing V8"); } ImplementationUtilities::HandleScopeData* ImplementationUtilities::CurrentHandleScope() { return &i::HandleScope::current_; } #ifdef DEBUG void ImplementationUtilities::ZapHandleRange(i::Object** begin, i::Object** end) { i::HandleScope::ZapRange(begin, end); } #endif v8::Handle ImplementationUtilities::Undefined() { if (!EnsureInitialized("v8::Undefined()")) return v8::Handle(); return v8::Handle(ToApi(i::Factory::undefined_value())); } v8::Handle ImplementationUtilities::Null() { if (!EnsureInitialized("v8::Null()")) return v8::Handle(); return v8::Handle(ToApi(i::Factory::null_value())); } v8::Handle ImplementationUtilities::True() { if (!EnsureInitialized("v8::True()")) return v8::Handle(); return v8::Handle(ToApi(i::Factory::true_value())); } v8::Handle ImplementationUtilities::False() { if (!EnsureInitialized("v8::False()")) return v8::Handle(); return v8::Handle(ToApi(i::Factory::false_value())); } void V8::SetFlagsFromString(const char* str, int length) { i::FlagList::SetFlagsFromString(str, length); } void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) { i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags); } v8::Handle ThrowException(v8::Handle value) { if (IsDeadCheck("v8::ThrowException()")) return v8::Handle(); ENTER_V8; // If we're passed an empty handle, we throw an undefined exception // to deal more gracefully with out of memory situations. if (value.IsEmpty()) { i::Top::ScheduleThrow(i::Heap::undefined_value()); } else { i::Top::ScheduleThrow(*Utils::OpenHandle(*value)); } return v8::Undefined(); } RegisteredExtension* RegisteredExtension::first_extension_ = NULL; RegisteredExtension::RegisteredExtension(Extension* extension) : extension_(extension), state_(UNVISITED) { } void RegisteredExtension::Register(RegisteredExtension* that) { that->next_ = RegisteredExtension::first_extension_; RegisteredExtension::first_extension_ = that; } void RegisterExtension(Extension* that) { RegisteredExtension* extension = new RegisteredExtension(that); RegisteredExtension::Register(extension); } Extension::Extension(const char* name, const char* source, int dep_count, const char** deps) : name_(name), source_(source), dep_count_(dep_count), deps_(deps), auto_enable_(false) { } v8::Handle Undefined() { LOG_API("Undefined"); return ImplementationUtilities::Undefined(); } v8::Handle Null() { LOG_API("Null"); return ImplementationUtilities::Null(); } v8::Handle True() { LOG_API("True"); return ImplementationUtilities::True(); } v8::Handle False() { LOG_API("False"); return ImplementationUtilities::False(); } ResourceConstraints::ResourceConstraints() : max_young_space_size_(0), max_old_space_size_(0), stack_limit_(NULL) { } bool SetResourceConstraints(ResourceConstraints* constraints) { int young_space_size = constraints->max_young_space_size(); int old_gen_size = constraints->max_old_space_size(); if (young_space_size != 0 || old_gen_size != 0) { bool result = i::Heap::ConfigureHeap(young_space_size / 2, old_gen_size); if (!result) return false; } if (constraints->stack_limit() != NULL) { uintptr_t limit = reinterpret_cast(constraints->stack_limit()); i::StackGuard::SetStackLimit(limit); } return true; } i::Object** V8::GlobalizeReference(i::Object** obj) { if (IsDeadCheck("V8::Persistent::New")) return NULL; LOG_API("Persistent::New"); i::Handle result = i::GlobalHandles::Create(*obj); return result.location(); } void V8::MakeWeak(i::Object** object, void* parameters, WeakReferenceCallback callback) { LOG_API("MakeWeak"); i::GlobalHandles::MakeWeak(object, parameters, callback); } void V8::ClearWeak(i::Object** obj) { LOG_API("ClearWeak"); i::GlobalHandles::ClearWeakness(obj); } bool V8::IsGlobalNearDeath(i::Object** obj) { LOG_API("IsGlobalNearDeath"); if (!i::V8::IsRunning()) return false; return i::GlobalHandles::IsNearDeath(obj); } bool V8::IsGlobalWeak(i::Object** obj) { LOG_API("IsGlobalWeak"); if (!i::V8::IsRunning()) return false; return i::GlobalHandles::IsWeak(obj); } void V8::DisposeGlobal(i::Object** obj) { LOG_API("DisposeGlobal"); if (!i::V8::IsRunning()) return; i::GlobalHandles::Destroy(obj); } // --- H a n d l e s --- HandleScope::HandleScope() : is_closed_(false) { API_ENTRY_CHECK("HandleScope::HandleScope"); i::HandleScope::Enter(&previous_); } HandleScope::~HandleScope() { if (!is_closed_) { i::HandleScope::Leave(&previous_); } } int HandleScope::NumberOfHandles() { return i::HandleScope::NumberOfHandles(); } i::Object** v8::HandleScope::CreateHandle(i::Object* value) { return i::HandleScope::CreateHandle(value); } void Context::Enter() { if (IsDeadCheck("v8::Context::Enter()")) return; ENTER_V8; i::Handle env = Utils::OpenHandle(this); thread_local.EnterContext(env); thread_local.SaveContext(i::Top::context()); i::Top::set_context(*env); } void Context::Exit() { if (!i::V8::IsRunning()) return; if (!ApiCheck(thread_local.LeaveLastContext(), "v8::Context::Exit()", "Cannot exit non-entered context")) { return; } // Content of 'last_context' could be NULL. i::Context* last_context = thread_local.RestoreContext(); i::Top::set_context(last_context); } void Context::SetData(v8::Handle data) { if (IsDeadCheck("v8::Context::SetData()")) return; ENTER_V8; { HandleScope scope; i::Handle env = Utils::OpenHandle(this); i::Handle raw_data = Utils::OpenHandle(*data); ASSERT(env->IsGlobalContext()); if (env->IsGlobalContext()) { env->set_data(*raw_data); } } } v8::Local Context::GetData() { if (IsDeadCheck("v8::Context::GetData()")) return v8::Local(); ENTER_V8; i::Object* raw_result = NULL; { HandleScope scope; i::Handle env = Utils::OpenHandle(this); ASSERT(env->IsGlobalContext()); if (env->IsGlobalContext()) { raw_result = env->data(); } else { return Local(); } } i::Handle result(raw_result); return Utils::ToLocal(result); } i::Object** v8::HandleScope::RawClose(i::Object** value) { if (!ApiCheck(!is_closed_, "v8::HandleScope::Close()", "Local scope has already been closed")) { return 0; } LOG_API("CloseHandleScope"); // Read the result before popping the handle block. i::Object* result = NULL; if (value != NULL) { result = *value; } is_closed_ = true; i::HandleScope::Leave(&previous_); if (value == NULL) { return NULL; } // Allocate a new handle on the previous handle block. i::Handle handle(result); return handle.location(); } // --- N e a n d e r --- // A constructor cannot easily return an error value, therefore it is necessary // to check for a dead VM with ON_BAILOUT before constructing any Neander // objects. To remind you about this there is no HandleScope in the // NeanderObject constructor. When you add one to the site calling the // constructor you should check that you ensured the VM was not dead first. NeanderObject::NeanderObject(int size) { EnsureInitialized("v8::Nowhere"); ENTER_V8; value_ = i::Factory::NewNeanderObject(); i::Handle elements = i::Factory::NewFixedArray(size); value_->set_elements(*elements); } int NeanderObject::size() { return i::FixedArray::cast(value_->elements())->length(); } NeanderArray::NeanderArray() : obj_(2) { obj_.set(0, i::Smi::FromInt(0)); } int NeanderArray::length() { return i::Smi::cast(obj_.get(0))->value(); } i::Object* NeanderArray::get(int offset) { ASSERT(0 <= offset); ASSERT(offset < length()); return obj_.get(offset + 1); } // This method cannot easily return an error value, therefore it is necessary // to check for a dead VM with ON_BAILOUT before calling it. To remind you // about this there is no HandleScope in this method. When you add one to the // site calling this method you should check that you ensured the VM was not // dead first. void NeanderArray::add(i::Handle value) { int length = this->length(); int size = obj_.size(); if (length == size - 1) { i::Handle new_elms = i::Factory::NewFixedArray(2 * size); for (int i = 0; i < length; i++) new_elms->set(i + 1, get(i)); obj_.value()->set_elements(*new_elms); } obj_.set(length + 1, *value); obj_.set(0, i::Smi::FromInt(length + 1)); } void NeanderArray::set(int index, i::Object* value) { if (index < 0 || index >= this->length()) return; obj_.set(index + 1, value); } // --- T e m p l a t e --- static void InitializeTemplate(i::Handle that, int type) { that->set_tag(i::Smi::FromInt(type)); } void Template::Set(v8::Handle name, v8::Handle value, v8::PropertyAttribute attribute) { if (IsDeadCheck("v8::Template::SetProperty()")) return; ENTER_V8; HandleScope scope; i::Handle list(Utils::OpenHandle(this)->property_list()); if (list->IsUndefined()) { list = NeanderArray().value(); Utils::OpenHandle(this)->set_property_list(*list); } NeanderArray array(list); array.add(Utils::OpenHandle(*name)); array.add(Utils::OpenHandle(*value)); array.add(Utils::OpenHandle(*v8::Integer::New(attribute))); } // --- F u n c t i o n T e m p l a t e --- static void InitializeFunctionTemplate( i::Handle info) { info->set_tag(i::Smi::FromInt(Consts::FUNCTION_TEMPLATE)); info->set_flag(0); } Local FunctionTemplate::PrototypeTemplate() { if (IsDeadCheck("v8::FunctionTemplate::PrototypeTemplate()")) { return Local(); } ENTER_V8; i::Handle result(Utils::OpenHandle(this)->prototype_template()); if (result->IsUndefined()) { result = Utils::OpenHandle(*ObjectTemplate::New()); Utils::OpenHandle(this)->set_prototype_template(*result); } return Local(ToApi(result)); } void FunctionTemplate::Inherit(v8::Handle value) { if (IsDeadCheck("v8::FunctionTemplate::Inherit()")) return; ENTER_V8; Utils::OpenHandle(this)->set_parent_template(*Utils::OpenHandle(*value)); } // To distinguish the function templates, so that we can find them in the // function cache of the global context. static int next_serial_number = 0; Local FunctionTemplate::New(InvocationCallback callback, v8::Handle data, v8::Handle signature) { EnsureInitialized("v8::FunctionTemplate::New()"); LOG_API("FunctionTemplate::New"); ENTER_V8; i::Handle struct_obj = i::Factory::NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); InitializeFunctionTemplate(obj); obj->set_serial_number(i::Smi::FromInt(next_serial_number++)); if (callback != 0) { if (data.IsEmpty()) data = v8::Undefined(); Utils::ToLocal(obj)->SetCallHandler(callback, data); } obj->set_undetectable(false); obj->set_needs_access_check(false); if (!signature.IsEmpty()) obj->set_signature(*Utils::OpenHandle(*signature)); return Utils::ToLocal(obj); } Local Signature::New(Handle receiver, int argc, Handle argv[]) { EnsureInitialized("v8::Signature::New()"); LOG_API("Signature::New"); ENTER_V8; i::Handle struct_obj = i::Factory::NewStruct(i::SIGNATURE_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); if (!receiver.IsEmpty()) obj->set_receiver(*Utils::OpenHandle(*receiver)); if (argc > 0) { i::Handle args = i::Factory::NewFixedArray(argc); for (int i = 0; i < argc; i++) { if (!argv[i].IsEmpty()) args->set(i, *Utils::OpenHandle(*argv[i])); } obj->set_args(*args); } return Utils::ToLocal(obj); } Local TypeSwitch::New(Handle type) { Handle types[1] = { type }; return TypeSwitch::New(1, types); } Local TypeSwitch::New(int argc, Handle types[]) { EnsureInitialized("v8::TypeSwitch::New()"); LOG_API("TypeSwitch::New"); ENTER_V8; i::Handle vector = i::Factory::NewFixedArray(argc); for (int i = 0; i < argc; i++) vector->set(i, *Utils::OpenHandle(*types[i])); i::Handle struct_obj = i::Factory::NewStruct(i::TYPE_SWITCH_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); obj->set_types(*vector); return Utils::ToLocal(obj); } int TypeSwitch::match(v8::Handle value) { LOG_API("TypeSwitch::match"); i::Handle obj = Utils::OpenHandle(*value); i::Handle info = Utils::OpenHandle(this); i::FixedArray* types = i::FixedArray::cast(info->types()); for (int i = 0; i < types->length(); i++) { if (obj->IsInstanceOf(i::FunctionTemplateInfo::cast(types->get(i)))) return i + 1; } return 0; } void FunctionTemplate::SetCallHandler(InvocationCallback callback, v8::Handle data) { if (IsDeadCheck("v8::FunctionTemplate::SetCallHandler()")) return; ENTER_V8; HandleScope scope; i::Handle struct_obj = i::Factory::NewStruct(i::CALL_HANDLER_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); obj->set_callback(*FromCData(callback)); if (data.IsEmpty()) data = v8::Undefined(); obj->set_data(*Utils::OpenHandle(*data)); Utils::OpenHandle(this)->set_call_code(*obj); } static i::Handle MakeAccessorInfo( v8::Handle name, AccessorGetter getter, AccessorSetter setter, v8::Handle data, v8::AccessControl settings, v8::PropertyAttribute attributes) { i::Handle obj = i::Factory::NewAccessorInfo(); ASSERT(getter != NULL); obj->set_getter(*FromCData(getter)); obj->set_setter(*FromCData(setter)); if (data.IsEmpty()) data = v8::Undefined(); obj->set_data(*Utils::OpenHandle(*data)); obj->set_name(*Utils::OpenHandle(*name)); if (settings & ALL_CAN_READ) obj->set_all_can_read(true); if (settings & ALL_CAN_WRITE) obj->set_all_can_write(true); if (settings & PROHIBITS_OVERWRITING) obj->set_prohibits_overwriting(true); obj->set_property_attributes(static_cast(attributes)); return obj; } void FunctionTemplate::AddInstancePropertyAccessor( v8::Handle name, AccessorGetter getter, AccessorSetter setter, v8::Handle data, v8::AccessControl settings, v8::PropertyAttribute attributes) { if (IsDeadCheck("v8::FunctionTemplate::AddInstancePropertyAccessor()")) { return; } ENTER_V8; HandleScope scope; i::Handle obj = MakeAccessorInfo(name, getter, setter, data, settings, attributes); i::Handle list(Utils::OpenHandle(this)->property_accessors()); if (list->IsUndefined()) { list = NeanderArray().value(); Utils::OpenHandle(this)->set_property_accessors(*list); } NeanderArray array(list); array.add(obj); } Local FunctionTemplate::InstanceTemplate() { if (IsDeadCheck("v8::FunctionTemplate::InstanceTemplate()") || EmptyCheck("v8::FunctionTemplate::InstanceTemplate()", this)) return Local(); ENTER_V8; if (Utils::OpenHandle(this)->instance_template()->IsUndefined()) { Local templ = ObjectTemplate::New(v8::Handle(this)); Utils::OpenHandle(this)->set_instance_template(*Utils::OpenHandle(*templ)); } i::Handle result(i::ObjectTemplateInfo::cast( Utils::OpenHandle(this)->instance_template())); return Utils::ToLocal(result); } void FunctionTemplate::SetClassName(Handle name) { if (IsDeadCheck("v8::FunctionTemplate::SetClassName()")) return; ENTER_V8; Utils::OpenHandle(this)->set_class_name(*Utils::OpenHandle(*name)); } void FunctionTemplate::SetHiddenPrototype(bool value) { if (IsDeadCheck("v8::FunctionTemplate::SetHiddenPrototype()")) return; ENTER_V8; Utils::OpenHandle(this)->set_hidden_prototype(value); } void FunctionTemplate::SetNamedInstancePropertyHandler( NamedPropertyGetter getter, NamedPropertySetter setter, NamedPropertyQuery query, NamedPropertyDeleter remover, NamedPropertyEnumerator enumerator, Handle data) { if (IsDeadCheck("v8::FunctionTemplate::SetNamedInstancePropertyHandler()")) { return; } ENTER_V8; HandleScope scope; i::Handle struct_obj = i::Factory::NewStruct(i::INTERCEPTOR_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); if (getter != 0) obj->set_getter(*FromCData(getter)); if (setter != 0) obj->set_setter(*FromCData(setter)); if (query != 0) obj->set_query(*FromCData(query)); if (remover != 0) obj->set_deleter(*FromCData(remover)); if (enumerator != 0) obj->set_enumerator(*FromCData(enumerator)); if (data.IsEmpty()) data = v8::Undefined(); obj->set_data(*Utils::OpenHandle(*data)); Utils::OpenHandle(this)->set_named_property_handler(*obj); } void FunctionTemplate::SetIndexedInstancePropertyHandler( IndexedPropertyGetter getter, IndexedPropertySetter setter, IndexedPropertyQuery query, IndexedPropertyDeleter remover, IndexedPropertyEnumerator enumerator, Handle data) { if (IsDeadCheck( "v8::FunctionTemplate::SetIndexedInstancePropertyHandler()")) { return; } ENTER_V8; HandleScope scope; i::Handle struct_obj = i::Factory::NewStruct(i::INTERCEPTOR_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); if (getter != 0) obj->set_getter(*FromCData(getter)); if (setter != 0) obj->set_setter(*FromCData(setter)); if (query != 0) obj->set_query(*FromCData(query)); if (remover != 0) obj->set_deleter(*FromCData(remover)); if (enumerator != 0) obj->set_enumerator(*FromCData(enumerator)); if (data.IsEmpty()) data = v8::Undefined(); obj->set_data(*Utils::OpenHandle(*data)); Utils::OpenHandle(this)->set_indexed_property_handler(*obj); } void FunctionTemplate::SetInstanceCallAsFunctionHandler( InvocationCallback callback, Handle data) { if (IsDeadCheck("v8::FunctionTemplate::SetInstanceCallAsFunctionHandler()")) { return; } ENTER_V8; HandleScope scope; i::Handle struct_obj = i::Factory::NewStruct(i::CALL_HANDLER_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); obj->set_callback(*FromCData(callback)); if (data.IsEmpty()) data = v8::Undefined(); obj->set_data(*Utils::OpenHandle(*data)); Utils::OpenHandle(this)->set_instance_call_handler(*obj); } // --- O b j e c t T e m p l a t e --- Local ObjectTemplate::New() { return New(Local()); } Local ObjectTemplate::New( v8::Handle constructor) { if (IsDeadCheck("v8::ObjectTemplate::New()")) return Local(); EnsureInitialized("v8::ObjectTemplate::New()"); LOG_API("ObjectTemplate::New"); ENTER_V8; i::Handle struct_obj = i::Factory::NewStruct(i::OBJECT_TEMPLATE_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); InitializeTemplate(obj, Consts::OBJECT_TEMPLATE); if (!constructor.IsEmpty()) obj->set_constructor(*Utils::OpenHandle(*constructor)); obj->set_internal_field_count(i::Smi::FromInt(0)); return Utils::ToLocal(obj); } // Ensure that the object template has a constructor. If no // constructor is available we create one. static void EnsureConstructor(ObjectTemplate* object_template) { if (Utils::OpenHandle(object_template)->constructor()->IsUndefined()) { Local templ = FunctionTemplate::New(); i::Handle constructor = Utils::OpenHandle(*templ); constructor->set_instance_template(*Utils::OpenHandle(object_template)); Utils::OpenHandle(object_template)->set_constructor(*constructor); } } void ObjectTemplate::SetAccessor(v8::Handle name, AccessorGetter getter, AccessorSetter setter, v8::Handle data, AccessControl settings, PropertyAttribute attribute) { if (IsDeadCheck("v8::ObjectTemplate::SetAccessor()")) return; ENTER_V8; HandleScope scope; EnsureConstructor(this); i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); i::Handle cons(constructor); Utils::ToLocal(cons)->AddInstancePropertyAccessor(name, getter, setter, data, settings, attribute); } void ObjectTemplate::SetNamedPropertyHandler(NamedPropertyGetter getter, NamedPropertySetter setter, NamedPropertyQuery query, NamedPropertyDeleter remover, NamedPropertyEnumerator enumerator, Handle data) { if (IsDeadCheck("v8::ObjectTemplate::SetNamedPropertyHandler()")) return; ENTER_V8; HandleScope scope; EnsureConstructor(this); i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); i::Handle cons(constructor); Utils::ToLocal(cons)->SetNamedInstancePropertyHandler(getter, setter, query, remover, enumerator, data); } void ObjectTemplate::MarkAsUndetectable() { if (IsDeadCheck("v8::ObjectTemplate::MarkAsUndetectable()")) return; ENTER_V8; HandleScope scope; EnsureConstructor(this); i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); i::Handle cons(constructor); cons->set_undetectable(true); } void ObjectTemplate::SetAccessCheckCallbacks( NamedSecurityCallback named_callback, IndexedSecurityCallback indexed_callback, Handle data, bool turned_on_by_default) { if (IsDeadCheck("v8::ObjectTemplate::SetAccessCheckCallbacks()")) return; ENTER_V8; HandleScope scope; EnsureConstructor(this); i::Handle struct_info = i::Factory::NewStruct(i::ACCESS_CHECK_INFO_TYPE); i::Handle info = i::Handle::cast(struct_info); info->set_named_callback(*FromCData(named_callback)); info->set_indexed_callback(*FromCData(indexed_callback)); if (data.IsEmpty()) data = v8::Undefined(); info->set_data(*Utils::OpenHandle(*data)); i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); i::Handle cons(constructor); cons->set_access_check_info(*info); cons->set_needs_access_check(turned_on_by_default); } void ObjectTemplate::SetIndexedPropertyHandler( IndexedPropertyGetter getter, IndexedPropertySetter setter, IndexedPropertyQuery query, IndexedPropertyDeleter remover, IndexedPropertyEnumerator enumerator, Handle data) { if (IsDeadCheck("v8::ObjectTemplate::SetIndexedPropertyHandler()")) return; ENTER_V8; HandleScope scope; EnsureConstructor(this); i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); i::Handle cons(constructor); Utils::ToLocal(cons)->SetIndexedInstancePropertyHandler(getter, setter, query, remover, enumerator, data); } void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback, Handle data) { if (IsDeadCheck("v8::ObjectTemplate::SetCallAsFunctionHandler()")) return; ENTER_V8; HandleScope scope; EnsureConstructor(this); i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor()); i::Handle cons(constructor); Utils::ToLocal(cons)->SetInstanceCallAsFunctionHandler(callback, data); } int ObjectTemplate::InternalFieldCount() { if (IsDeadCheck("v8::ObjectTemplate::InternalFieldCount()")) { return 0; } return i::Smi::cast(Utils::OpenHandle(this)->internal_field_count())->value(); } void ObjectTemplate::SetInternalFieldCount(int value) { if (IsDeadCheck("v8::ObjectTemplate::SetInternalFieldCount()")) return; if (!ApiCheck(i::Smi::IsValid(value), "v8::ObjectTemplate::SetInternalFieldCount()", "Invalid internal field count")) { return; } ENTER_V8; if (value > 0) { // The internal field count is set by the constructor function's // construct code, so we ensure that there is a constructor // function to do the setting. EnsureConstructor(this); } Utils::OpenHandle(this)->set_internal_field_count(i::Smi::FromInt(value)); } // --- S c r i p t D a t a --- ScriptData* ScriptData::PreCompile(const char* input, int length) { unibrow::Utf8InputBuffer<> buf(input, length); return i::PreParse(i::Handle(), &buf, NULL); } ScriptData* ScriptData::PreCompile(v8::Handle source) { i::Handle str = Utils::OpenHandle(*source); return i::PreParse(str, NULL, NULL); } ScriptData* ScriptData::New(const char* data, int length) { // Return an empty ScriptData if the length is obviously invalid. if (length % sizeof(unsigned) != 0) { return new i::ScriptDataImpl(i::Vector()); } // Copy the data to ensure it is properly aligned. int deserialized_data_length = length / sizeof(unsigned); unsigned* deserialized_data = i::NewArray(deserialized_data_length); memcpy(deserialized_data, data, length); return new i::ScriptDataImpl( i::Vector(deserialized_data, deserialized_data_length)); } // --- S c r i p t --- Local