// Copyright 2011 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 "deoptimizer.h" #include "execution.h" #include "flags.h" #include "global-handles.h" #include "heap-profiler.h" #include "messages.h" #include "natives.h" #include "parser.h" #include "platform.h" #include "profile-generator-inl.h" #include "runtime-profiler.h" #include "serialize.h" #include "snapshot.h" #include "v8threads.h" #include "version.h" #include "vm-state-inl.h" #include "../include/v8-profiler.h" #include "../include/v8-testing.h" #define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr)) #define ENTER_V8(isolate) \ ASSERT((isolate)->IsInitialized()); \ i::VMState __state__((isolate), i::OTHER) #define LEAVE_V8(isolate) \ i::VMState __state__((isolate), i::EXTERNAL) namespace v8 { #define ON_BAILOUT(isolate, location, code) \ if (IsDeadCheck(isolate, location) || \ IsExecutionTerminatingCheck(isolate)) { \ code; \ UNREACHABLE(); \ } #define EXCEPTION_PREAMBLE(isolate) \ (isolate)->handle_scope_implementer()->IncrementCallDepth(); \ ASSERT(!(isolate)->external_caught_exception()); \ bool has_pending_exception = false #define EXCEPTION_BAILOUT_CHECK(isolate, value) \ do { \ i::HandleScopeImplementer* handle_scope_implementer = \ (isolate)->handle_scope_implementer(); \ handle_scope_implementer->DecrementCallDepth(); \ if (has_pending_exception) { \ if (handle_scope_implementer->CallDepthIsZero() && \ (isolate)->is_out_of_memory()) { \ if (!(isolate)->ignore_out_of_memory()) \ i::V8::FatalProcessOutOfMemory(NULL); \ } \ bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero(); \ (isolate)->OptionalRescheduleException(call_depth_is_zero); \ return value; \ } \ } while (false) #define API_ENTRY_CHECK(isolate, msg) \ do { \ if (v8::Locker::IsActive()) { \ ApiCheck(isolate->thread_manager()->IsLockedByCurrentThread(), \ msg, \ "Entering the V8 API without proper locking in place"); \ } \ } while (false) // --- E x c e p t i o n B e h a v i o r --- static void DefaultFatalErrorHandler(const char* location, const char* message) { i::VMState __state__(i::Isolate::Current(), i::OTHER); API_Fatal(location, message); } static FatalErrorCallback GetFatalErrorHandler() { i::Isolate* isolate = i::Isolate::Current(); if (isolate->exception_behavior() == NULL) { isolate->set_exception_behavior(DefaultFatalErrorHandler); } return isolate->exception_behavior(); } void i::FatalProcessOutOfMemory(const char* location) { i::V8::FatalProcessOutOfMemory(location, false); } // 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; intptr_t old_pointer_space_size; heap_stats.old_pointer_space_size = &old_pointer_space_size; intptr_t old_pointer_space_capacity; heap_stats.old_pointer_space_capacity = &old_pointer_space_capacity; intptr_t old_data_space_size; heap_stats.old_data_space_size = &old_data_space_size; intptr_t old_data_space_capacity; heap_stats.old_data_space_capacity = &old_data_space_capacity; intptr_t code_space_size; heap_stats.code_space_size = &code_space_size; intptr_t code_space_capacity; heap_stats.code_space_capacity = &code_space_capacity; intptr_t map_space_size; heap_stats.map_space_size = &map_space_size; intptr_t map_space_capacity; heap_stats.map_space_capacity = &map_space_capacity; intptr_t cell_space_size; heap_stats.cell_space_size = &cell_space_size; intptr_t cell_space_capacity; heap_stats.cell_space_capacity = &cell_space_capacity; intptr_t 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 free_global_handle_count; heap_stats.free_global_handle_count = &free_global_handle_count; intptr_t memory_allocator_size; heap_stats.memory_allocator_size = &memory_allocator_size; intptr_t 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::Isolate* isolate = i::Isolate::Current(); isolate->heap()->RecordStats(&heap_stats, take_snapshot); i::V8::SetFatalError(); FatalErrorCallback callback = GetFatalErrorHandler(); { LEAVE_V8(isolate); callback(location, "Allocation failed - process out of memory"); } // If the callback returns, we stop execution. UNREACHABLE(); } 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(i::Isolate* isolate, const char* location) { return !isolate->IsInitialized() && i::V8::IsDead() ? ReportV8Dead(location) : false; } static inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) { if (!isolate->IsInitialized()) return false; if (isolate->has_scheduled_exception()) { return isolate->scheduled_exception() == isolate->heap()->termination_exception(); } return 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 bool InitializeHelper() { if (i::Snapshot::Initialize()) return true; return i::V8::Initialize(NULL); } static inline bool EnsureInitializedForIsolate(i::Isolate* isolate, const char* location) { if (IsDeadCheck(isolate, location)) return false; if (isolate != NULL) { if (isolate->IsInitialized()) return true; } ASSERT(isolate == i::Isolate::Current()); return ApiCheck(InitializeHelper(), location, "Error initializing V8"); } // Some initializing API functions are called early and may be // called on a thread different from static initializer thread. // If Isolate API is used, Isolate::Enter() will initialize TLS so // Isolate::Current() works. If it's a legacy case, then the thread // may not have TLS initialized yet. However, in initializing APIs it // may be too early to call EnsureInitialized() - some pre-init // parameters still have to be configured. static inline i::Isolate* EnterIsolateIfNeeded() { i::Isolate* isolate = i::Isolate::UncheckedCurrent(); if (isolate != NULL) return isolate; i::Isolate::EnterDefaultIsolate(); isolate = i::Isolate::Current(); return isolate; } StartupDataDecompressor::StartupDataDecompressor() : raw_data(i::NewArray(V8::GetCompressedStartupDataCount())) { for (int i = 0; i < V8::GetCompressedStartupDataCount(); ++i) { raw_data[i] = NULL; } } StartupDataDecompressor::~StartupDataDecompressor() { for (int i = 0; i < V8::GetCompressedStartupDataCount(); ++i) { i::DeleteArray(raw_data[i]); } i::DeleteArray(raw_data); } int StartupDataDecompressor::Decompress() { int compressed_data_count = V8::GetCompressedStartupDataCount(); StartupData* compressed_data = i::NewArray(compressed_data_count); V8::GetCompressedStartupData(compressed_data); for (int i = 0; i < compressed_data_count; ++i) { char* decompressed = raw_data[i] = i::NewArray(compressed_data[i].raw_size); if (compressed_data[i].compressed_size != 0) { int result = DecompressData(decompressed, &compressed_data[i].raw_size, compressed_data[i].data, compressed_data[i].compressed_size); if (result != 0) return result; } else { ASSERT_EQ(0, compressed_data[i].raw_size); } compressed_data[i].data = decompressed; } V8::SetDecompressedStartupData(compressed_data); return 0; } StartupData::CompressionAlgorithm V8::GetCompressedStartupDataAlgorithm() { #ifdef COMPRESS_STARTUP_DATA_BZ2 return StartupData::kBZip2; #else return StartupData::kUncompressed; #endif } enum CompressedStartupDataItems { kSnapshot = 0, kSnapshotContext, kLibraries, kExperimentalLibraries, kCompressedStartupDataCount }; int V8::GetCompressedStartupDataCount() { #ifdef COMPRESS_STARTUP_DATA_BZ2 return kCompressedStartupDataCount; #else return 0; #endif } void V8::GetCompressedStartupData(StartupData* compressed_data) { #ifdef COMPRESS_STARTUP_DATA_BZ2 compressed_data[kSnapshot].data = reinterpret_cast(i::Snapshot::data()); compressed_data[kSnapshot].compressed_size = i::Snapshot::size(); compressed_data[kSnapshot].raw_size = i::Snapshot::raw_size(); compressed_data[kSnapshotContext].data = reinterpret_cast(i::Snapshot::context_data()); compressed_data[kSnapshotContext].compressed_size = i::Snapshot::context_size(); compressed_data[kSnapshotContext].raw_size = i::Snapshot::context_raw_size(); i::Vector libraries_source = i::Natives::GetScriptsSource(); compressed_data[kLibraries].data = reinterpret_cast(libraries_source.start()); compressed_data[kLibraries].compressed_size = libraries_source.length(); compressed_data[kLibraries].raw_size = i::Natives::GetRawScriptsSize(); i::Vector exp_libraries_source = i::ExperimentalNatives::GetScriptsSource(); compressed_data[kExperimentalLibraries].data = reinterpret_cast(exp_libraries_source.start()); compressed_data[kExperimentalLibraries].compressed_size = exp_libraries_source.length(); compressed_data[kExperimentalLibraries].raw_size = i::ExperimentalNatives::GetRawScriptsSize(); #endif } void V8::SetDecompressedStartupData(StartupData* decompressed_data) { #ifdef COMPRESS_STARTUP_DATA_BZ2 ASSERT_EQ(i::Snapshot::raw_size(), decompressed_data[kSnapshot].raw_size); i::Snapshot::set_raw_data( reinterpret_cast(decompressed_data[kSnapshot].data)); ASSERT_EQ(i::Snapshot::context_raw_size(), decompressed_data[kSnapshotContext].raw_size); i::Snapshot::set_context_raw_data( reinterpret_cast( decompressed_data[kSnapshotContext].data)); ASSERT_EQ(i::Natives::GetRawScriptsSize(), decompressed_data[kLibraries].raw_size); i::Vector libraries_source( decompressed_data[kLibraries].data, decompressed_data[kLibraries].raw_size); i::Natives::SetRawScriptsSource(libraries_source); ASSERT_EQ(i::ExperimentalNatives::GetRawScriptsSize(), decompressed_data[kExperimentalLibraries].raw_size); i::Vector exp_libraries_source( decompressed_data[kExperimentalLibraries].data, decompressed_data[kExperimentalLibraries].raw_size); i::ExperimentalNatives::SetRawScriptsSource(exp_libraries_source); #endif } void V8::SetFatalErrorHandler(FatalErrorCallback that) { i::Isolate* isolate = EnterIsolateIfNeeded(); isolate->set_exception_behavior(that); } void V8::SetAllowCodeGenerationFromStringsCallback( AllowCodeGenerationFromStringsCallback callback) { i::Isolate* isolate = EnterIsolateIfNeeded(); isolate->set_allow_code_gen_callback(callback); } #ifdef DEBUG void ImplementationUtilities::ZapHandleRange(i::Object** begin, i::Object** end) { i::HandleScope::ZapRange(begin, end); } #endif 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) { i::Isolate* isolate = i::Isolate::Current(); if (IsDeadCheck(isolate, "v8::ThrowException()")) { return v8::Handle(); } ENTER_V8(isolate); // If we're passed an empty handle, we throw an undefined exception // to deal more gracefully with out of memory situations. if (value.IsEmpty()) { isolate->ScheduleThrow(isolate->heap()->undefined_value()); } else { isolate->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_ = first_extension_; 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() { i::Isolate* isolate = i::Isolate::Current(); if (!EnsureInitializedForIsolate(isolate, "v8::Undefined()")) { return v8::Handle(); } return v8::Handle(ToApi( isolate->factory()->undefined_value())); } v8::Handle Null() { i::Isolate* isolate = i::Isolate::Current(); if (!EnsureInitializedForIsolate(isolate, "v8::Null()")) { return v8::Handle(); } return v8::Handle( ToApi(isolate->factory()->null_value())); } v8::Handle True() { i::Isolate* isolate = i::Isolate::Current(); if (!EnsureInitializedForIsolate(isolate, "v8::True()")) { return v8::Handle(); } return v8::Handle( ToApi(isolate->factory()->true_value())); } v8::Handle False() { i::Isolate* isolate = i::Isolate::Current(); if (!EnsureInitializedForIsolate(isolate, "v8::False()")) { return v8::Handle(); } return v8::Handle( ToApi(isolate->factory()->false_value())); } ResourceConstraints::ResourceConstraints() : max_young_space_size_(0), max_old_space_size_(0), max_executable_size_(0), stack_limit_(NULL) { } bool SetResourceConstraints(ResourceConstraints* constraints) { i::Isolate* isolate = EnterIsolateIfNeeded(); int young_space_size = constraints->max_young_space_size(); int old_gen_size = constraints->max_old_space_size(); int max_executable_size = constraints->max_executable_size(); if (young_space_size != 0 || old_gen_size != 0 || max_executable_size != 0) { // After initialization it's too late to change Heap constraints. ASSERT(!isolate->IsInitialized()); bool result = isolate->heap()->ConfigureHeap(young_space_size / 2, old_gen_size, max_executable_size); if (!result) return false; } if (constraints->stack_limit() != NULL) { uintptr_t limit = reinterpret_cast(constraints->stack_limit()); isolate->stack_guard()->SetStackLimit(limit); } return true; } i::Object** V8::GlobalizeReference(i::Object** obj) { i::Isolate* isolate = i::Isolate::Current(); if (IsDeadCheck(isolate, "V8::Persistent::New")) return NULL; LOG_API(isolate, "Persistent::New"); i::Handle result = isolate->global_handles()->Create(*obj); return result.location(); } void V8::MakeWeak(i::Object** object, void* parameters, WeakReferenceCallback callback) { i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "MakeWeak"); isolate->global_handles()->MakeWeak(object, parameters, callback); } void V8::ClearWeak(i::Object** obj) { i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "ClearWeak"); isolate->global_handles()->ClearWeakness(obj); } void V8::MarkIndependent(i::Object** object) { i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "MakeIndependent"); isolate->global_handles()->MarkIndependent(object); } bool V8::IsGlobalNearDeath(i::Object** obj) { i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "IsGlobalNearDeath"); if (!isolate->IsInitialized()) return false; return i::GlobalHandles::IsNearDeath(obj); } bool V8::IsGlobalWeak(i::Object** obj) { i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "IsGlobalWeak"); if (!isolate->IsInitialized()) return false; return i::GlobalHandles::IsWeak(obj); } void V8::DisposeGlobal(i::Object** obj) { i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "DisposeGlobal"); if (!isolate->IsInitialized()) return; isolate->global_handles()->Destroy(obj); } // --- H a n d l e s --- HandleScope::HandleScope() { i::Isolate* isolate = i::Isolate::Current(); API_ENTRY_CHECK(isolate, "HandleScope::HandleScope"); v8::ImplementationUtilities::HandleScopeData* current = isolate->handle_scope_data(); isolate_ = isolate; prev_next_ = current->next; prev_limit_ = current->limit; is_closed_ = false; current->level++; } HandleScope::~HandleScope() { if (!is_closed_) { Leave(); } } void HandleScope::Leave() { ASSERT(isolate_ == i::Isolate::Current()); v8::ImplementationUtilities::HandleScopeData* current = isolate_->handle_scope_data(); current->level--; ASSERT(current->level >= 0); current->next = prev_next_; if (current->limit != prev_limit_) { current->limit = prev_limit_; i::HandleScope::DeleteExtensions(isolate_); } #ifdef DEBUG i::HandleScope::ZapRange(prev_next_, prev_limit_); #endif } int HandleScope::NumberOfHandles() { EnsureInitializedForIsolate( i::Isolate::Current(), "HandleScope::NumberOfHandles"); return i::HandleScope::NumberOfHandles(); } i::Object** HandleScope::CreateHandle(i::Object* value) { return i::HandleScope::CreateHandle(value, i::Isolate::Current()); } i::Object** HandleScope::CreateHandle(i::HeapObject* value) { ASSERT(value->IsHeapObject()); return reinterpret_cast( i::HandleScope::CreateHandle(value, value->GetIsolate())); } void Context::Enter() { i::Handle env = Utils::OpenHandle(this); i::Isolate* isolate = env->GetIsolate(); if (IsDeadCheck(isolate, "v8::Context::Enter()")) return; ENTER_V8(isolate); isolate->handle_scope_implementer()->EnterContext(env); isolate->handle_scope_implementer()->SaveContext(isolate->context()); isolate->set_context(*env); } void Context::Exit() { // Exit is essentially a static function and doesn't use the // receiver, so we have to get the current isolate from the thread // local. i::Isolate* isolate = i::Isolate::Current(); if (!isolate->IsInitialized()) return; if (!ApiCheck(isolate->handle_scope_implementer()->LeaveLastContext(), "v8::Context::Exit()", "Cannot exit non-entered context")) { return; } // Content of 'last_context' could be NULL. i::Context* last_context = isolate->handle_scope_implementer()->RestoreContext(); isolate->set_context(last_context); } void Context::SetData(v8::Handle data) { i::Handle env = Utils::OpenHandle(this); i::Isolate* isolate = env->GetIsolate(); if (IsDeadCheck(isolate, "v8::Context::SetData()")) return; i::Handle raw_data = Utils::OpenHandle(*data); ASSERT(env->IsGlobalContext()); if (env->IsGlobalContext()) { env->set_data(*raw_data); } } v8::Local Context::GetData() { i::Handle env = Utils::OpenHandle(this); i::Isolate* isolate = env->GetIsolate(); if (IsDeadCheck(isolate, "v8::Context::GetData()")) { return v8::Local(); } i::Object* raw_result = NULL; ASSERT(env->IsGlobalContext()); if (env->IsGlobalContext()) { raw_result = env->data(); } else { return Local(); } i::Handle result(raw_result, isolate); 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(isolate_, "CloseHandleScope"); // Read the result before popping the handle block. i::Object* result = NULL; if (value != NULL) { result = *value; } is_closed_ = true; Leave(); 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) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::Nowhere"); ENTER_V8(isolate); value_ = isolate->factory()->NewNeanderObject(); i::Handle elements = isolate->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 = 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) { i::Isolate* isolate = i::Isolate::Current(); if (IsDeadCheck(isolate, "v8::Template::Set()")) return; ENTER_V8(isolate); i::HandleScope scope(isolate); 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() { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::PrototypeTemplate()")) { return Local(); } ENTER_V8(isolate); 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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::Inherit()")) return; ENTER_V8(isolate); Utils::OpenHandle(this)->set_parent_template(*Utils::OpenHandle(*value)); } Local FunctionTemplate::New(InvocationCallback callback, v8::Handle data, v8::Handle signature) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::FunctionTemplate::New()"); LOG_API(isolate, "FunctionTemplate::New"); ENTER_V8(isolate); i::Handle struct_obj = isolate->factory()->NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); InitializeFunctionTemplate(obj); int next_serial_number = isolate->next_serial_number(); isolate->set_next_serial_number(next_serial_number + 1); 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[]) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::Signature::New()"); LOG_API(isolate, "Signature::New"); ENTER_V8(isolate); i::Handle struct_obj = isolate->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 = isolate->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[]) { i::Isolate* isolate = i::Isolate::Current(); EnsureInitializedForIsolate(isolate, "v8::TypeSwitch::New()"); LOG_API(isolate, "TypeSwitch::New"); ENTER_V8(isolate); i::Handle vector = isolate->factory()->NewFixedArray(argc); for (int i = 0; i < argc; i++) vector->set(i, *Utils::OpenHandle(*types[i])); i::Handle struct_obj = isolate->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) { i::Isolate* isolate = i::Isolate::Current(); LOG_API(isolate, "TypeSwitch::match"); USE(isolate); 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; } #define SET_FIELD_WRAPPED(obj, setter, cdata) do { \ i::Handle foreign = FromCData(cdata); \ (obj)->setter(*foreign); \ } while (false) void FunctionTemplate::SetCallHandler(InvocationCallback callback, v8::Handle data) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetCallHandler()")) return; ENTER_V8(isolate); i::HandleScope scope(isolate); i::Handle struct_obj = isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); SET_FIELD_WRAPPED(obj, set_callback, 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 = FACTORY->NewAccessorInfo(); ASSERT(getter != NULL); SET_FIELD_WRAPPED(obj, set_getter, getter); SET_FIELD_WRAPPED(obj, set_setter, 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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::AddInstancePropertyAccessor()")) { return; } ENTER_V8(isolate); i::HandleScope scope(isolate); 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() { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::InstanceTemplate()") || EmptyCheck("v8::FunctionTemplate::InstanceTemplate()", this)) return Local(); ENTER_V8(isolate); 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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetClassName()")) return; ENTER_V8(isolate); Utils::OpenHandle(this)->set_class_name(*Utils::OpenHandle(*name)); } void FunctionTemplate::SetHiddenPrototype(bool value) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetHiddenPrototype()")) { return; } ENTER_V8(isolate); Utils::OpenHandle(this)->set_hidden_prototype(value); } void FunctionTemplate::ReadOnlyPrototype() { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetPrototypeAttributes()")) { return; } ENTER_V8(isolate); Utils::OpenHandle(this)->set_read_only_prototype(true); } void FunctionTemplate::SetNamedInstancePropertyHandler( NamedPropertyGetter getter, NamedPropertySetter setter, NamedPropertyQuery query, NamedPropertyDeleter remover, NamedPropertyEnumerator enumerator, Handle data) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetNamedInstancePropertyHandler()")) { return; } ENTER_V8(isolate); i::HandleScope scope(isolate); i::Handle struct_obj = isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter); if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter); if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query); if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, 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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetIndexedInstancePropertyHandler()")) { return; } ENTER_V8(isolate); i::HandleScope scope(isolate); i::Handle struct_obj = isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter); if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter); if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query); if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, 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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetInstanceCallAsFunctionHandler()")) { return; } ENTER_V8(isolate); i::HandleScope scope(isolate); i::Handle struct_obj = isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE); i::Handle obj = i::Handle::cast(struct_obj); SET_FIELD_WRAPPED(obj, set_callback, 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) { i::Isolate* isolate = i::Isolate::Current(); if (IsDeadCheck(isolate, "v8::ObjectTemplate::New()")) { return Local(); } EnsureInitializedForIsolate(isolate, "v8::ObjectTemplate::New()"); LOG_API(isolate, "ObjectTemplate::New"); ENTER_V8(isolate); i::Handle struct_obj = isolate->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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return; ENTER_V8(isolate); i::HandleScope scope(isolate); 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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetNamedPropertyHandler()")) { return; } ENTER_V8(isolate); i::HandleScope scope(isolate); 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() { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::ObjectTemplate::MarkAsUndetectable()")) return; ENTER_V8(isolate); i::HandleScope scope(isolate); 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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessCheckCallbacks()")) { return; } ENTER_V8(isolate); i::HandleScope scope(isolate); EnsureConstructor(this); i::Handle struct_info = isolate->factory()->NewStruct(i::ACCESS_CHECK_INFO_TYPE); i::Handle info = i::Handle::cast(struct_info); SET_FIELD_WRAPPED(info, set_named_callback, named_callback); SET_FIELD_WRAPPED(info, set_indexed_callback, 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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetIndexedPropertyHandler()")) { return; } ENTER_V8(isolate); i::HandleScope scope(isolate); 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) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetCallAsFunctionHandler()")) { return; } ENTER_V8(isolate); i::HandleScope scope(isolate); 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(Utils::OpenHandle(this)->GetIsolate(), "v8::ObjectTemplate::InternalFieldCount()")) { return 0; } return i::Smi::cast(Utils::OpenHandle(this)->internal_field_count())->value(); } void ObjectTemplate::SetInternalFieldCount(int value) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetInternalFieldCount()")) { return; } if (!ApiCheck(i::Smi::IsValid(value), "v8::ObjectTemplate::SetInternalFieldCount()", "Invalid internal field count")) { return; } ENTER_V8(isolate); 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) { i::Utf8ToUC16CharacterStream stream( reinterpret_cast(input), length); return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping); } ScriptData* ScriptData::PreCompile(v8::Handle source) { i::Handle str = Utils::OpenHandle(*source); if (str->IsExternalTwoByteString()) { i::ExternalTwoByteStringUC16CharacterStream stream( i::Handle::cast(str), 0, str->length()); return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping); } else { i::GenericStringUC16CharacterStream stream(str, 0, str->length()); return i::ParserApi::PreParse(&stream, NULL, i::FLAG_harmony_block_scoping); } } 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(); } // Copy the data to ensure it is properly aligned. int deserialized_data_length = length / sizeof(unsigned); // If aligned, don't create a copy of the data. if (reinterpret_cast(data) % sizeof(unsigned) == 0) { return new i::ScriptDataImpl(data, length); } // Copy the data to align it. unsigned* deserialized_data = i::NewArray(deserialized_data_length); i::OS::MemCopy(deserialized_data, data, length); return new i::ScriptDataImpl( i::Vector(deserialized_data, deserialized_data_length)); } // --- S c r i p t --- Local