From 679147eead574d186ebf3069647b4c23e8ccace6 Mon Sep 17 00:00:00 2001 From: Zeno Albisser Date: Thu, 15 Aug 2013 21:46:11 +0200 Subject: Initial import. --- chromium/v8/src/api.cc | 8182 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 8182 insertions(+) create mode 100644 chromium/v8/src/api.cc (limited to 'chromium/v8/src/api.cc') diff --git a/chromium/v8/src/api.cc b/chromium/v8/src/api.cc new file mode 100644 index 00000000000..eb2ffcff180 --- /dev/null +++ b/chromium/v8/src/api.cc @@ -0,0 +1,8182 @@ +// Copyright 2012 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 "api.h" + +#include // For memcpy, strlen. +#include // For isnan. +#include "../include/v8-debug.h" +#include "../include/v8-profiler.h" +#include "../include/v8-testing.h" +#include "assert-scope.h" +#include "bootstrapper.h" +#include "code-stubs.h" +#include "compiler.h" +#include "conversions-inl.h" +#include "counters.h" +#include "cpu-profiler.h" +#include "debug.h" +#include "deoptimizer.h" +#include "execution.h" +#include "global-handles.h" +#include "heap-profiler.h" +#include "heap-snapshot-generator-inl.h" +#include "icu_util.h" +#include "json-parser.h" +#include "messages.h" +#ifdef COMPRESS_STARTUP_DATA_BZ2 +#include "natives.h" +#endif +#include "parser.h" +#include "platform.h" +#include "profile-generator-inl.h" +#include "property-details.h" +#include "property.h" +#include "runtime.h" +#include "runtime-profiler.h" +#include "scanner-character-streams.h" +#include "snapshot.h" +#include "unicode-inl.h" +#include "v8threads.h" +#include "version.h" +#include "vm-state-inl.h" + + +#define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr)) + +#define ENTER_V8(isolate) \ + ASSERT((isolate)->IsInitialized()); \ + i::VMState __state__((isolate)) + +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_GENERIC(isolate, value, do_callback) \ + 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); \ + do_callback \ + return value; \ + } \ + do_callback \ + } while (false) + + +#define EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, value) \ + EXCEPTION_BAILOUT_CHECK_GENERIC( \ + isolate, value, i::V8::FireCallCompletedCallback(isolate);) + + +#define EXCEPTION_BAILOUT_CHECK(isolate, value) \ + EXCEPTION_BAILOUT_CHECK_GENERIC(isolate, value, ;) + + +#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::Isolate* isolate = i::Isolate::Current(); + if (isolate->IsInitialized()) { + i::VMState state(isolate); + API_Fatal(location, message); + } else { + 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 property_cell_space_size; + heap_stats.property_cell_space_size = &property_cell_space_size; + intptr_t property_cell_space_capacity; + heap_stats.property_cell_space_capacity = &property_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(); + if (isolate->heap()->HasBeenSetUp()) { + // BUG(1718): Don't use the take_snapshot since we don't support + // HeapIterator here without doing a special GC. + isolate->heap()->RecordStats(&heap_stats, false); + } + i::V8::SetFatalError(); + FatalErrorCallback callback = GetFatalErrorHandler(); + const char* message = "Allocation failed - process out of memory"; + callback(location, message); + // 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(i::Isolate* isolate) { + // If the isolate has a function entry hook, it needs to re-build all its + // code stubs with entry hooks embedded, so let's deserialize a snapshot. + if (isolate == NULL || isolate->function_entry_hook() == NULL) { + 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(isolate), 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); + i::DeleteArray(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, +#if defined(V8_I18N_SUPPORT) + kI18NExtension, +#endif + 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(); + +#if defined(V8_I18N_SUPPORT) + i::Vector i18n_extension_source = + i::I18NNatives::GetScriptsSource(); + compressed_data[kI18NExtension].data = + reinterpret_cast(i18n_extension_source.start()); + compressed_data[kI18NExtension].compressed_size = + i18n_extension_source.length(); + compressed_data[kI18NExtension].raw_size = + i::I18NNatives::GetRawScriptsSize(); +#endif +#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); + +#if defined(V8_I18N_SUPPORT) + ASSERT_EQ(i::I18NNatives::GetRawScriptsSize(), + decompressed_data[kI18NExtension].raw_size); + i::Vector i18n_extension_source( + decompressed_data[kI18NExtension].data, + decompressed_data[kI18NExtension].raw_size); + i::I18NNatives::SetRawScriptsSource(i18n_extension_source); +#endif +#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); +} + + +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) { } + + +void RegisteredExtension::Register(RegisteredExtension* that) { + that->next_ = first_extension_; + first_extension_ = that; +} + + +void RegisteredExtension::UnregisterAll() { + RegisteredExtension* re = first_extension_; + while (re != NULL) { + RegisteredExtension* next = re->next(); + delete re; + re = next; + } +} + + +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, + int source_length) + : name_(name), + source_length_(source_length >= 0 ? + source_length : + (source ? static_cast(strlen(source)) : 0)), + source_(source, source_length_), + dep_count_(dep_count), + deps_(deps), + auto_enable_(false) { + CHECK(source != NULL || source_length_ == 0); +} + + +v8::Handle Undefined() { + i::Isolate* isolate = i::Isolate::Current(); + if (!EnsureInitializedForIsolate(isolate, "v8::Undefined()")) { + return v8::Handle(); + } + return ToApiHandle(isolate->factory()->undefined_value()); +} + + +v8::Handle Null() { + i::Isolate* isolate = i::Isolate::Current(); + if (!EnsureInitializedForIsolate(isolate, "v8::Null()")) { + return v8::Handle(); + } + return ToApiHandle(isolate->factory()->null_value()); +} + + +v8::Handle True() { + i::Isolate* isolate = i::Isolate::Current(); + if (!EnsureInitializedForIsolate(isolate, "v8::True()")) { + return v8::Handle(); + } + return ToApiHandle(isolate->factory()->true_value()); +} + + +v8::Handle False() { + i::Isolate* isolate = i::Isolate::Current(); + if (!EnsureInitializedForIsolate(isolate, "v8::False()")) { + return v8::Handle(); + } + return ToApiHandle(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::Isolate* isolate, i::Object** obj) { + if (IsDeadCheck(isolate, "V8::Persistent::New")) return NULL; + LOG_API(isolate, "Persistent::New"); + i::Handle result = isolate->global_handles()->Create(*obj); +#ifdef DEBUG + (*obj)->Verify(); +#endif // DEBUG + return result.location(); +} + + +void V8::MakeWeak(i::Object** object, + void* parameters, + RevivableCallback weak_reference_callback) { + i::GlobalHandles::MakeWeak(object, + parameters, + weak_reference_callback); +} + + +void V8::ClearWeak(i::Object** obj) { + i::GlobalHandles::ClearWeakness(obj); +} + + +void V8::DisposeGlobal(i::Object** obj) { + i::GlobalHandles::Destroy(obj); +} + + +int V8::Eternalize(i::Isolate* isolate, i::Object** handle) { + return isolate->eternal_handles()->Create(isolate, *handle); +} + + +i::Object** V8::GetEternal(i::Isolate* isolate, int index) { + return isolate->eternal_handles()->Get(index).location(); +} + + +// --- H a n d l e s --- + + +HandleScope::HandleScope() { + Initialize(reinterpret_cast(i::Isolate::Current())); +} + + +HandleScope::HandleScope(Isolate* isolate) { + Initialize(isolate); +} + + +void HandleScope::Initialize(Isolate* isolate) { + i::Isolate* internal_isolate = reinterpret_cast(isolate); + API_ENTRY_CHECK(internal_isolate, "HandleScope::HandleScope"); + v8::ImplementationUtilities::HandleScopeData* current = + internal_isolate->handle_scope_data(); + isolate_ = internal_isolate; + prev_next_ = current->next; + prev_limit_ = current->limit; + is_closed_ = false; + current->level++; +} + + +HandleScope::~HandleScope() { + if (!is_closed_) { + Leave(); + } +} + + +void HandleScope::Leave() { + return i::HandleScope::CloseScope(isolate_, prev_next_, prev_limit_); +} + + +int HandleScope::NumberOfHandles() { + i::Isolate* isolate = i::Isolate::Current(); + if (!EnsureInitializedForIsolate(isolate, "HandleScope::NumberOfHandles")) { + return 0; + } + return i::HandleScope::NumberOfHandles(isolate); +} + + +i::Object** HandleScope::CreateHandle(i::Object* value) { + return i::HandleScope::CreateHandle(i::Isolate::Current(), value); +} + + +i::Object** HandleScope::CreateHandle(i::Isolate* isolate, i::Object* value) { + ASSERT(isolate == i::Isolate::Current()); + return i::HandleScope::CreateHandle(isolate, value); +} + + +i::Object** HandleScope::CreateHandle(i::HeapObject* value) { + ASSERT(value->IsHeapObject()); + return reinterpret_cast( + i::HandleScope::CreateHandle(value->GetIsolate(), value)); +} + + +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); +} + + +static void* DecodeSmiToAligned(i::Object* value, const char* location) { + ApiCheck(value->IsSmi(), location, "Not a Smi"); + return reinterpret_cast(value); +} + + +static i::Smi* EncodeAlignedAsSmi(void* value, const char* location) { + i::Smi* smi = reinterpret_cast(value); + ApiCheck(smi->IsSmi(), location, "Pointer is not aligned"); + return smi; +} + + +static i::Handle EmbedderDataFor(Context* context, + int index, + bool can_grow, + const char* location) { + i::Handle env = Utils::OpenHandle(context); + bool ok = !IsDeadCheck(env->GetIsolate(), location) && + ApiCheck(env->IsNativeContext(), location, "Not a native context") && + ApiCheck(index >= 0, location, "Negative index"); + if (!ok) return i::Handle(); + i::Handle data(env->embedder_data()); + if (index < data->length()) return data; + if (!can_grow) { + Utils::ReportApiFailure(location, "Index too large"); + return i::Handle(); + } + int new_size = i::Max(index, data->length() << 1) + 1; + data = env->GetIsolate()->factory()->CopySizeFixedArray(data, new_size); + env->set_embedder_data(*data); + return data; +} + + +v8::Local Context::SlowGetEmbedderData(int index) { + const char* location = "v8::Context::GetEmbedderData()"; + i::Handle data = EmbedderDataFor(this, index, false, location); + if (data.is_null()) return Local(); + i::Handle result(data->get(index), data->GetIsolate()); + return Utils::ToLocal(result); +} + + +void Context::SetEmbedderData(int index, v8::Handle value) { + const char* location = "v8::Context::SetEmbedderData()"; + i::Handle data = EmbedderDataFor(this, index, true, location); + if (data.is_null()) return; + i::Handle val = Utils::OpenHandle(*value); + data->set(index, *val); + ASSERT_EQ(*Utils::OpenHandle(*value), + *Utils::OpenHandle(*GetEmbedderData(index))); +} + + +void* Context::SlowGetAlignedPointerFromEmbedderData(int index) { + const char* location = "v8::Context::GetAlignedPointerFromEmbedderData()"; + i::Handle data = EmbedderDataFor(this, index, false, location); + if (data.is_null()) return NULL; + return DecodeSmiToAligned(data->get(index), location); +} + + +void Context::SetAlignedPointerInEmbedderData(int index, void* value) { + const char* location = "v8::Context::SetAlignedPointerInEmbedderData()"; + i::Handle data = EmbedderDataFor(this, index, true, location); + data->set(index, EncodeAlignedAsSmi(value, location)); + ASSERT_EQ(value, GetAlignedPointerFromEmbedderData(index)); +} + + +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, isolate_); + 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::Factory* factory = i::Isolate::Current()->factory(); + 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(), isolate); + 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(), + isolate); + if (result->IsUndefined()) { + result = Utils::OpenHandle(*ObjectTemplate::New()); + Utils::OpenHandle(this)->set_prototype_template(*result); + } + return ToApiHandle(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)); +} + + +// TODO(dcarney): Remove this abstraction when old callbacks are removed. +class CallHandlerHelper { + public: + static inline void Set(Local function_template, + InvocationCallback callback, + v8::Handle data) { + function_template->SetCallHandlerInternal(callback, data); + } + static inline void Set(Local function_template, + FunctionCallback callback, + v8::Handle data) { + function_template->SetCallHandler(callback, data); + } +}; + + +template +static Local FunctionTemplateNew( + Callback callback, + v8::Handle data, + v8::Handle signature, + int length) { + 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(); + CallHandlerHelper::Set(Utils::ToLocal(obj), callback, data); + } + obj->set_length(length); + obj->set_undetectable(false); + obj->set_needs_access_check(false); + + if (!signature.IsEmpty()) + obj->set_signature(*Utils::OpenHandle(*signature)); + return Utils::ToLocal(obj); +} + + +Local FunctionTemplate::New( + InvocationCallback callback, + v8::Handle data, + v8::Handle signature, + int length) { + return FunctionTemplateNew(callback, data, signature, length); +} + + +Local FunctionTemplate::New( + FunctionCallback callback, + v8::Handle data, + v8::Handle signature, + int length) { + return FunctionTemplateNew(callback, data, signature, length); +} + + +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 AccessorSignature::New( + Handle receiver) { + return Utils::AccessorSignatureToLocal(Utils::OpenHandle(*receiver)); +} + + +template +static Local NewDescriptor( + Isolate* isolate, + const i::DeclaredAccessorDescriptorData& data, + Data* previous_descriptor) { + i::Isolate* internal_isolate = reinterpret_cast(isolate); + i::Handle previous = + i::Handle(); + if (previous_descriptor != NULL) { + previous = Utils::OpenHandle( + static_cast(previous_descriptor)); + } + i::Handle descriptor = + i::DeclaredAccessorDescriptor::Create(internal_isolate, data, previous); + return Utils::Convert(descriptor); +} + + +Local + ObjectOperationDescriptor::NewInternalFieldDereference( + Isolate* isolate, + int internal_field) { + i::DeclaredAccessorDescriptorData data; + data.type = i::kDescriptorObjectDereference; + data.object_dereference_descriptor.internal_field = internal_field; + return NewDescriptor(isolate, data, NULL); +} + + +Local RawOperationDescriptor::NewRawShift( + Isolate* isolate, + int16_t byte_offset) { + i::DeclaredAccessorDescriptorData data; + data.type = i::kDescriptorPointerShift; + data.pointer_shift_descriptor.byte_offset = byte_offset; + return NewDescriptor(isolate, data, this); +} + + +Local RawOperationDescriptor::NewHandleDereference( + Isolate* isolate) { + i::DeclaredAccessorDescriptorData data; + data.type = i::kDescriptorReturnObject; + return NewDescriptor(isolate, data, this); +} + + +Local RawOperationDescriptor::NewRawDereference( + Isolate* isolate) { + i::DeclaredAccessorDescriptorData data; + data.type = i::kDescriptorPointerDereference; + return NewDescriptor(isolate, data, this); +} + + +Local RawOperationDescriptor::NewPointerCompare( + Isolate* isolate, + void* compare_value) { + i::DeclaredAccessorDescriptorData data; + data.type = i::kDescriptorPointerCompare; + data.pointer_compare_descriptor.compare_value = compare_value; + return NewDescriptor(isolate, data, this); +} + + +Local RawOperationDescriptor::NewPrimitiveValue( + Isolate* isolate, + DeclaredAccessorDescriptorDataType data_type, + uint8_t bool_offset) { + i::DeclaredAccessorDescriptorData data; + data.type = i::kDescriptorPrimitiveValue; + data.primitive_value_descriptor.data_type = data_type; + data.primitive_value_descriptor.bool_offset = bool_offset; + return NewDescriptor(isolate, data, this); +} + + +template +static Local NewBitmaskCompare( + Isolate* isolate, + T bitmask, + T compare_value, + RawOperationDescriptor* operation) { + i::DeclaredAccessorDescriptorData data; + data.type = i::kDescriptorBitmaskCompare; + data.bitmask_compare_descriptor.bitmask = bitmask; + data.bitmask_compare_descriptor.compare_value = compare_value; + data.bitmask_compare_descriptor.size = sizeof(T); + return NewDescriptor(isolate, data, operation); +} + + +Local RawOperationDescriptor::NewBitmaskCompare8( + Isolate* isolate, + uint8_t bitmask, + uint8_t compare_value) { + return NewBitmaskCompare(isolate, bitmask, compare_value, this); +} + + +Local RawOperationDescriptor::NewBitmaskCompare16( + Isolate* isolate, + uint16_t bitmask, + uint16_t compare_value) { + return NewBitmaskCompare(isolate, bitmask, compare_value, this); +} + + +Local RawOperationDescriptor::NewBitmaskCompare32( + Isolate* isolate, + uint32_t bitmask, + uint32_t compare_value) { + return NewBitmaskCompare(isolate, bitmask, compare_value, this); +} + + +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) + + +template +static void FunctionTemplateSetCallHandler(FunctionTemplate* function_template, + Callback callback_in, + v8::Handle data) { + i::Isolate* isolate = Utils::OpenHandle(function_template)->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); + FunctionCallback callback = + i::CallbackTable::Register(isolate, callback_in); + SET_FIELD_WRAPPED(obj, set_callback, callback); + if (data.IsEmpty()) data = v8::Undefined(); + obj->set_data(*Utils::OpenHandle(*data)); + Utils::OpenHandle(function_template)->set_call_code(*obj); +} + +void FunctionTemplate::SetCallHandler(InvocationCallback callback, + v8::Handle data) { + FunctionTemplateSetCallHandler(this, callback, data); +} + +void FunctionTemplate::SetCallHandlerInternal(InvocationCallback callback, + v8::Handle data) { + FunctionTemplateSetCallHandler(this, callback, data); +} + +void FunctionTemplate::SetCallHandler(FunctionCallback callback, + v8::Handle data) { + FunctionTemplateSetCallHandler(this, callback, data); +} + +static i::Handle SetAccessorInfoProperties( + i::Handle obj, + v8::Handle name, + v8::AccessControl settings, + v8::PropertyAttribute attributes, + v8::Handle signature) { + 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)); + if (!signature.IsEmpty()) { + obj->set_expected_receiver_type(*Utils::OpenHandle(*signature)); + } + return obj; +} + + +template +static i::Handle MakeAccessorInfo( + v8::Handle name, + Getter getter_in, + Setter setter_in, + v8::Handle data, + v8::AccessControl settings, + v8::PropertyAttribute attributes, + v8::Handle signature) { + i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate(); + i::Handle obj = + isolate->factory()->NewExecutableAccessorInfo(); + AccessorGetterCallback getter = + i::CallbackTable::Register(isolate, getter_in); + SET_FIELD_WRAPPED(obj, set_getter, getter); + AccessorSetterCallback setter = + i::CallbackTable::Register(isolate, setter_in); + SET_FIELD_WRAPPED(obj, set_setter, setter); + if (data.IsEmpty()) data = v8::Undefined(); + obj->set_data(*Utils::OpenHandle(*data)); + return SetAccessorInfoProperties(obj, name, settings, attributes, signature); +} + + +static i::Handle MakeAccessorInfo( + v8::Handle name, + v8::Handle descriptor, + void* setter_ignored, + void* data_ignored, + v8::AccessControl settings, + v8::PropertyAttribute attributes, + v8::Handle signature) { + i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate(); + if (descriptor.IsEmpty()) return i::Handle(); + i::Handle obj = + isolate->factory()->NewDeclaredAccessorInfo(); + obj->set_descriptor(*Utils::OpenHandle(*descriptor)); + return SetAccessorInfoProperties(obj, name, settings, attributes, signature); +} + + +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); + i::Handle handle = Utils::OpenHandle(this); + if (handle->instance_template()->IsUndefined()) { + Local templ = + ObjectTemplate::New(ToApiHandle(handle)); + handle->set_instance_template(*Utils::OpenHandle(*templ)); + } + i::Handle result( + i::ObjectTemplateInfo::cast(handle->instance_template())); + return Utils::ToLocal(result); +} + + +void FunctionTemplate::SetLength(int length) { + i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); + if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetLength()")) return; + ENTER_V8(isolate); + Utils::OpenHandle(this)->set_length(length); +} + + +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::ReadOnlyPrototype()")) { + return; + } + ENTER_V8(isolate); + Utils::OpenHandle(this)->set_read_only_prototype(true); +} + +template< + typename Getter, + typename Setter, + typename Query, + typename Deleter, + typename Enumerator> +static void SetNamedInstancePropertyHandler( + i::Handle function_template, + Getter getter_in, + Setter setter_in, + Query query_in, + Deleter remover_in, + Enumerator enumerator_in, + Handle data) { + i::Isolate* isolate = function_template->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); + + NamedPropertyGetterCallback getter = + i::CallbackTable::Register(isolate, getter_in); + if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter); + NamedPropertySetterCallback setter = + i::CallbackTable::Register(isolate, setter_in); + if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter); + NamedPropertyQueryCallback query = + i::CallbackTable::Register(isolate, query_in); + if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query); + NamedPropertyDeleterCallback remover = + i::CallbackTable::Register(isolate, remover_in); + if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); + NamedPropertyEnumeratorCallback enumerator = + i::CallbackTable::Register(isolate, enumerator_in); + if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator); + + if (data.IsEmpty()) data = v8::Undefined(); + obj->set_data(*Utils::OpenHandle(*data)); + function_template->set_named_property_handler(*obj); +} + + +template< + typename Getter, + typename Setter, + typename Query, + typename Deleter, + typename Enumerator> +static void SetIndexedInstancePropertyHandler( + i::Handle function_template, + Getter getter_in, + Setter setter_in, + Query query_in, + Deleter remover_in, + Enumerator enumerator_in, + Handle data) { + i::Isolate* isolate = function_template->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); + + IndexedPropertyGetterCallback getter = + i::CallbackTable::Register(isolate, getter_in); + if (getter != 0) SET_FIELD_WRAPPED(obj, set_getter, getter); + IndexedPropertySetterCallback setter = + i::CallbackTable::Register(isolate, setter_in); + if (setter != 0) SET_FIELD_WRAPPED(obj, set_setter, setter); + IndexedPropertyQueryCallback query = + i::CallbackTable::Register(isolate, query_in); + if (query != 0) SET_FIELD_WRAPPED(obj, set_query, query); + IndexedPropertyDeleterCallback remover = + i::CallbackTable::Register(isolate, remover_in); + if (remover != 0) SET_FIELD_WRAPPED(obj, set_deleter, remover); + IndexedPropertyEnumeratorCallback enumerator = + i::CallbackTable::Register(isolate, enumerator_in); + if (enumerator != 0) SET_FIELD_WRAPPED(obj, set_enumerator, enumerator); + + if (data.IsEmpty()) data = v8::Undefined(); + obj->set_data(*Utils::OpenHandle(*data)); + function_template->set_indexed_property_handler(*obj); +} + + +template +static void SetInstanceCallAsFunctionHandler( + i::Handle function_template, + Callback callback_in, + Handle data) { + i::Isolate* isolate = function_template->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); + FunctionCallback callback = + i::CallbackTable::Register(isolate, callback_in); + SET_FIELD_WRAPPED(obj, set_callback, callback); + if (data.IsEmpty()) data = v8::Undefined(); + obj->set_data(*Utils::OpenHandle(*data)); + function_template->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); + } +} + + +static inline void AddPropertyToFunctionTemplate( + i::Handle cons, + i::Handle obj) { + i::Handle list(cons->property_accessors(), cons->GetIsolate()); + if (list->IsUndefined()) { + list = NeanderArray().value(); + cons->set_property_accessors(*list); + } + NeanderArray array(list); + array.add(obj); +} + + +template +static bool ObjectTemplateSetAccessor( + ObjectTemplate* object_template, + v8::Handle name, + Getter getter, + Setter setter, + Data data, + AccessControl settings, + PropertyAttribute attribute, + v8::Handle signature) { + i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate(); + if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetAccessor()")) return false; + ENTER_V8(isolate); + i::HandleScope scope(isolate); + EnsureConstructor(object_template); + i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast( + Utils::OpenHandle(object_template)->constructor()); + i::Handle cons(constructor); + i::Handle obj = MakeAccessorInfo( + name, getter, setter, data, settings, attribute, signature); + if (obj.is_null()) return false; + AddPropertyToFunctionTemplate(cons, obj); + return true; +} + + +void ObjectTemplate::SetAccessor(v8::Handle name, + AccessorGetter getter, + AccessorSetter setter, + v8::Handle data, + AccessControl settings, + PropertyAttribute attribute, + v8::Handle signature) { + ObjectTemplateSetAccessor( + this, name, getter, setter, data, settings, attribute, signature); +} + + +void ObjectTemplate::SetAccessor(v8::Handle name, + AccessorGetterCallback getter, + AccessorSetterCallback setter, + v8::Handle data, + AccessControl settings, + PropertyAttribute attribute, + v8::Handle signature) { + ObjectTemplateSetAccessor( + this, name, getter, setter, data, settings, attribute, signature); +} + + +bool ObjectTemplate::SetAccessor(Handle name, + Handle descriptor, + AccessControl settings, + PropertyAttribute attribute, + Handle signature) { + void* null = NULL; + return ObjectTemplateSetAccessor( + this, name, descriptor, null, null, settings, attribute, signature); +} + + +template< + typename Getter, + typename Setter, + typename Query, + typename Deleter, + typename Enumerator> +static void ObjectTemplateSetNamedPropertyHandler( + ObjectTemplate* object_template, + Getter getter, + Setter setter, + Query query, + Deleter remover, + Enumerator enumerator, + Handle data) { + i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate(); + if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetNamedPropertyHandler()")) { + return; + } + ENTER_V8(isolate); + i::HandleScope scope(isolate); + EnsureConstructor(object_template); + i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast( + Utils::OpenHandle(object_template)->constructor()); + i::Handle cons(constructor); + SetNamedInstancePropertyHandler(cons, + getter, + setter, + query, + remover, + enumerator, + data); +} + + +void ObjectTemplate::SetNamedPropertyHandler( + NamedPropertyGetter getter, + NamedPropertySetter setter, + NamedPropertyQuery query, + NamedPropertyDeleter remover, + NamedPropertyEnumerator enumerator, + Handle data) { + ObjectTemplateSetNamedPropertyHandler( + this, getter, setter, query, remover, enumerator, data); +} + + +void ObjectTemplate::SetNamedPropertyHandler( + NamedPropertyGetterCallback getter, + NamedPropertySetterCallback setter, + NamedPropertyQueryCallback query, + NamedPropertyDeleterCallback remover, + NamedPropertyEnumeratorCallback enumerator, + Handle data) { + ObjectTemplateSetNamedPropertyHandler( + this, 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); +} + + +template< + typename Getter, + typename Setter, + typename Query, + typename Deleter, + typename Enumerator> +void ObjectTemplateSetIndexedPropertyHandler( + ObjectTemplate* object_template, + Getter getter, + Setter setter, + Query query, + Deleter remover, + Enumerator enumerator, + Handle data) { + i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate(); + if (IsDeadCheck(isolate, "v8::ObjectTemplate::SetIndexedPropertyHandler()")) { + return; + } + ENTER_V8(isolate); + i::HandleScope scope(isolate); + EnsureConstructor(object_template); + i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast( + Utils::OpenHandle(object_template)->constructor()); + i::Handle cons(constructor); + SetIndexedInstancePropertyHandler(cons, + getter, + setter, + query, + remover, + enumerator, + data); +} + + +void ObjectTemplate::SetIndexedPropertyHandler( + IndexedPropertyGetter getter, + IndexedPropertySetter setter, + IndexedPropertyQuery query, + IndexedPropertyDeleter remover, + IndexedPropertyEnumerator enumerator, + Handle data) { + ObjectTemplateSetIndexedPropertyHandler( + this, getter, setter, query, remover, enumerator, data); +} + + +void ObjectTemplate::SetIndexedPropertyHandler( + IndexedPropertyGetterCallback getter, + IndexedPropertySetterCallback setter, + IndexedPropertyQueryCallback query, + IndexedPropertyDeleterCallback remover, + IndexedPropertyEnumeratorCallback enumerator, + Handle data) { + ObjectTemplateSetIndexedPropertyHandler( + this, getter, setter, query, remover, enumerator, data); +} + + +template +static void ObjectTemplateSetCallAsFunctionHandler( + ObjectTemplate* object_template, + Callback callback, + Handle data) { + i::Isolate* isolate = Utils::OpenHandle(object_template)->GetIsolate(); + if (IsDeadCheck(isolate, + "v8::ObjectTemplate::SetCallAsFunctionHandler()")) { + return; + } + ENTER_V8(isolate); + i::HandleScope scope(isolate); + EnsureConstructor(object_template); + i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast( + Utils::OpenHandle(object_template)->constructor()); + i::Handle cons(constructor); + SetInstanceCallAsFunctionHandler(cons, callback, data); +} + + +void ObjectTemplate::SetCallAsFunctionHandler(InvocationCallback callback, + Handle data) { + return ObjectTemplateSetCallAsFunctionHandler(this, callback, data); +} + + +void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback, + Handle data) { + return ObjectTemplateSetCallAsFunctionHandler(this, 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::Utf8ToUtf16CharacterStream stream( + reinterpret_cast(input), length); + return i::PreParserApi::PreParse(&stream); +} + + +ScriptData* ScriptData::PreCompile(v8::Handle source) { + i::Handle str = Utils::OpenHandle(*source); + if (str->IsExternalTwoByteString()) { + i::ExternalTwoByteStringUtf16CharacterStream stream( + i::Handle::cast(str), 0, str->length()); + return i::PreParserApi::PreParse(&stream); + } else { + i::GenericStringUtf16CharacterStream stream(str, 0, str->length()); + return i::PreParserApi::PreParse(&stream); + } +} + + +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::CopyBytes(reinterpret_cast(deserialized_data), + data, static_cast(length)); + + return new i::ScriptDataImpl( + i::Vector(deserialized_data, deserialized_data_length)); +} + + +// --- S c r i p t --- + + +Local