// Copyright 2007-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. #include "v8.h" #include "api.h" #include "bootstrapper.h" #include "compiler.h" #include "debug.h" #include "execution.h" #include "global-handles.h" #include "platform.h" #include "serialize.h" #include "snapshot.h" namespace i = v8::internal; #define LOG_API(expr) LOG(ApiEntryCall(expr)) namespace v8 { #define ON_BAILOUT(location, code) \ if (IsDeadCheck(location)) { \ 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.IgnoreOutOfMemory()) \ i::V8::FatalProcessOutOfMemory(NULL); \ } \ bool call_depth_is_zero = thread_local.CallDepthIsZero(); \ i::Top::optional_reschedule_exception(call_depth_is_zero); \ return value; \ } \ } 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 bool has_shut_down = false; static FatalErrorCallback exception_behavior = NULL; static void DefaultFatalErrorHandler(const char* location, const char* message) { 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) { has_shut_down = true; FatalErrorCallback callback = GetFatalErrorHandler(); 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); has_shut_down = true; return false; } bool V8::IsDead() { return has_shut_down; } 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 useable"); 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 useable. 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 has_shut_down ? 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, v8::Data* obj) { return (obj == 0) ? ReportEmptyHandle(location) : false; } // --- S t a t i c s --- static i::StringInputBuffer write_input_buffer; static void EnsureInitialized(const char* location) { if (IsDeadCheck(location)) return; ApiCheck(v8::V8::Initialize(), location, "Error initializing V8"); } v8::Handle ImplementationUtilities::Undefined() { if (IsDeadCheck("v8::Undefined()")) return v8::Handle(); EnsureInitialized("v8::Undefined()"); return v8::Handle(ToApi(i::Factory::undefined_value())); } v8::Handle ImplementationUtilities::Null() { if (IsDeadCheck("v8::Null()")) return v8::Handle(); EnsureInitialized("v8::Null()"); return v8::Handle(ToApi(i::Factory::null_value())); } v8::Handle ImplementationUtilities::True() { if (IsDeadCheck("v8::True()")) return v8::Handle(); EnsureInitialized("v8::True()"); return v8::Handle(ToApi(i::Factory::true_value())); } v8::Handle ImplementationUtilities::False() { if (IsDeadCheck("v8::False()")) return v8::Handle(); EnsureInitialized("v8::False()"); return v8::Handle(ToApi(i::Factory::false_value())); } void V8::SetFlagsFromString(const char* str, int length) { i::FlagList::SetFlagsFromString(str, length); } v8::Handle ThrowException(v8::Handle value) { if (IsDeadCheck("v8::ThrowException()")) return v8::Handle(); 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) { bool result = i::Heap::ConfigureHeap(constraints->max_young_space_size(), constraints->max_old_space_size()); if (!result) return false; if (constraints->stack_limit() != NULL) { uintptr_t limit = reinterpret_cast(constraints->stack_limit()); i::StackGuard::SetStackLimit(limit); } return true; } void** V8::GlobalizeReference(void** obj) { LOG_API("Persistent::New"); if (IsDeadCheck("V8::Persistent::New")) return NULL; i::Handle result = i::GlobalHandles::Create(*reinterpret_cast(obj)); return reinterpret_cast(result.location()); } void V8::MakeWeak(void** object, void* parameters, WeakReferenceCallback callback) { LOG_API("MakeWeak"); i::GlobalHandles::MakeWeak(reinterpret_cast(object), parameters, callback); } void V8::ClearWeak(void** obj) { LOG_API("ClearWeak"); i::GlobalHandles::ClearWeakness(reinterpret_cast(obj)); } bool V8::IsGlobalNearDeath(void** obj) { LOG_API("IsGlobalNearDeath"); if (has_shut_down) return false; return i::GlobalHandles::IsNearDeath(reinterpret_cast(obj)); } bool V8::IsGlobalWeak(void** obj) { LOG_API("IsGlobalWeak"); if (has_shut_down) return false; return i::GlobalHandles::IsWeak(reinterpret_cast(obj)); } void V8::DisposeGlobal(void** obj) { LOG_API("DisposeGlobal"); if (has_shut_down) return; i::GlobalHandles::Destroy(reinterpret_cast(obj)); } // --- H a n d l e s --- HandleScope::Data HandleScope::current_ = { -1, NULL, NULL }; 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()); } 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; } } // 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 Context::Enter() { if (IsDeadCheck("v8::Context::Enter()")) return; i::Handle env = Utils::OpenHandle(this); thread_local.EnterContext(env); thread_local.SaveContext(i::GlobalHandles::Create(i::Top::context())); i::Top::set_context(*env); thread_local.SaveSecurityContext( i::GlobalHandles::Create(i::Top::security_context())); i::Top::set_security_context(*env); } void Context::Exit() { if (has_shut_down) return; if (!ApiCheck(thread_local.LeaveLastContext(), "v8::Context::Exit()", "Cannot exit non-entered context")) { return; } // Content of 'last_context' and 'last_security_context' could be NULL. i::Handle last_context = thread_local.RestoreContext(); i::Top::set_context(static_cast(*last_context)); i::GlobalHandles::Destroy(last_context.location()); i::Handle last_security_context = thread_local.RestoreSecurityContext(); i::Top::set_security_context( static_cast(*last_security_context)); i::GlobalHandles::Destroy(last_security_context.location()); } void v8::HandleScope::DeleteExtensions() { ASSERT(current_.extensions != 0); thread_local.DeleteExtensions(current_.extensions); } #ifdef DEBUG void HandleScope::ZapRange(void** start, void** end) { if (start == NULL) return; for (void** p = start; p < end; p++) { *p = reinterpret_cast(v8::internal::kHandleZapValue); } } #endif void** v8::HandleScope::RawClose(void** 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 = reinterpret_cast(*value); is_closed_ = true; RestorePreviousState(); // Allocate a new handle on the previous handle block. i::Handle handle(result); return reinterpret_cast(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"); 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; 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(); } 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; 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"); 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"); 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"); 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; 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); } void FunctionTemplate::SetLookupHandler(LookupCallback handler) { if (IsDeadCheck("v8::FunctionTemplate::SetLookupHandler()")) return; HandleScope scope; Utils::OpenHandle(this)->set_lookup_callback(*FromCData(handler)); } 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; } HandleScope scope; 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); obj->set_property_attributes(static_cast(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(); 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; Utils::OpenHandle(this)->set_class_name(*Utils::OpenHandle(*name)); } void FunctionTemplate::SetHiddenPrototype(bool value) { if (IsDeadCheck("v8::FunctionTemplate::SetHiddenPrototype()")) return; 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; } 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; } 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; } 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"); 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; 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; 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; 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) { if (IsDeadCheck("v8::ObjectTemplate::SetAccessCheckCallbacks()")) return; 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_needs_access_check(true); cons->set_access_check_info(*info); } void ObjectTemplate::SetIndexedPropertyHandler( IndexedPropertyGetter getter, IndexedPropertySetter setter, IndexedPropertyQuery query, IndexedPropertyDeleter remover, IndexedPropertyEnumerator enumerator, Handle data) { if (IsDeadCheck("v8::ObjectTemplate::SetIndexedPropertyHandler()")) return; 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; 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; } 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(&buf, NULL); } ScriptData* ScriptData::New(unsigned* data, int length) { return new i::ScriptDataImpl(i::Vector(data, length)); } // --- S c r i p t --- Local