blob: aee9e3a469eae454a9fdc7b241142050044a730a [file] [log] [blame]
// 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 <string.h> // For memcpy, strlen.
#include <cmath> // 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 "platform/time.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 "utils/random-number-generator.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<i::OTHER> __state__((isolate))
namespace v8 {
#define ON_BAILOUT(isolate, location, code) \
if (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<i::OTHER> 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);
}
isolate->SignalFatalError();
FatalErrorCallback callback = GetFatalErrorHandler();
const char* message = "Allocation failed - process out of memory";
callback(location, message);
// If the callback returns, we stop execution.
FATAL("API fatal error handler returned after process out of memory");
}
bool Utils::ReportApiFailure(const char* location, const char* message) {
FatalErrorCallback callback = GetFatalErrorHandler();
callback(location, message);
i::Isolate* isolate = i::Isolate::Current();
isolate->SignalFatalError();
return false;
}
bool V8::IsDead() {
i::Isolate* isolate = i::Isolate::Current();
return isolate->IsDead();
}
static inline bool ApiCheck(bool condition,
const char* location,
const char* message) {
return condition ? true : Utils::ReportApiFailure(location, message);
}
static bool ReportEmptyHandle(const char* location) {
FatalErrorCallback callback = GetFatalErrorHandler();
callback(location, "Reading from empty handle");
return true;
}
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<v8::Data> 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 (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<char*>(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<StartupData>(compressed_data_count);
V8::GetCompressedStartupData(compressed_data);
for (int i = 0; i < compressed_data_count; ++i) {
char* decompressed = raw_data[i] =
i::NewArray<char>(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,
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<const char*>(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<const char*>(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<const i::byte> libraries_source = i::Natives::GetScriptsSource();
compressed_data[kLibraries].data =
reinterpret_cast<const char*>(libraries_source.start());
compressed_data[kLibraries].compressed_size = libraries_source.length();
compressed_data[kLibraries].raw_size = i::Natives::GetRawScriptsSize();
i::Vector<const i::byte> exp_libraries_source =
i::ExperimentalNatives::GetScriptsSource();
compressed_data[kExperimentalLibraries].data =
reinterpret_cast<const char*>(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<const i::byte*>(decompressed_data[kSnapshot].data));
ASSERT_EQ(i::Snapshot::context_raw_size(),
decompressed_data[kSnapshotContext].raw_size);
i::Snapshot::set_context_raw_data(
reinterpret_cast<const i::byte*>(
decompressed_data[kSnapshotContext].data));
ASSERT_EQ(i::Natives::GetRawScriptsSize(),
decompressed_data[kLibraries].raw_size);
i::Vector<const char> 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<const char> 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);
}
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<Value> ThrowException(v8::Handle<v8::Value> value) {
return v8::Isolate::GetCurrent()->ThrowException(value);
}
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<int>(strlen(source)) : 0)),
source_(source, source_length_),
dep_count_(dep_count),
deps_(deps),
auto_enable_(false) {
CHECK(source != NULL || source_length_ == 0);
}
v8::Handle<Primitive> Undefined() {
i::Isolate* isolate = i::Isolate::Current();
if (!EnsureInitializedForIsolate(isolate, "v8::Undefined()")) {
return v8::Handle<v8::Primitive>();
}
return ToApiHandle<Primitive>(isolate->factory()->undefined_value());
}
v8::Handle<Primitive> Null() {
i::Isolate* isolate = i::Isolate::Current();
if (!EnsureInitializedForIsolate(isolate, "v8::Null()")) {
return v8::Handle<v8::Primitive>();
}
return ToApiHandle<Primitive>(isolate->factory()->null_value());
}
v8::Handle<Boolean> True() {
i::Isolate* isolate = i::Isolate::Current();
if (!EnsureInitializedForIsolate(isolate, "v8::True()")) {
return v8::Handle<Boolean>();
}
return ToApiHandle<Boolean>(isolate->factory()->true_value());
}
v8::Handle<Boolean> False() {
i::Isolate* isolate = i::Isolate::Current();
if (!EnsureInitializedForIsolate(isolate, "v8::False()")) {
return v8::Handle<Boolean>();
}
return ToApiHandle<Boolean>(isolate->factory()->false_value());
}
ResourceConstraints::ResourceConstraints()
: max_young_space_size_(0),
max_old_space_size_(0),
max_executable_size_(0),
stack_limit_(NULL),
max_available_threads_(0) { }
void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory,
uint32_t number_of_processors) {
const int lump_of_memory = (i::kPointerSize / 4) * i::MB;
#if V8_OS_ANDROID
// Android has higher physical memory requirements before raising the maximum
// heap size limits since it has no swap space.
const uint64_t low_limit = 512ul * i::MB;
const uint64_t medium_limit = 1ul * i::GB;
const uint64_t high_limit = 2ul * i::GB;
#else
const uint64_t low_limit = 512ul * i::MB;
const uint64_t medium_limit = 768ul * i::MB;
const uint64_t high_limit = 1ul * i::GB;
#endif
// The young_space_size should be a power of 2 and old_generation_size should
// be a multiple of Page::kPageSize.
if (physical_memory <= low_limit) {
set_max_young_space_size(2 * lump_of_memory);
set_max_old_space_size(128 * lump_of_memory);
set_max_executable_size(96 * lump_of_memory);
} else if (physical_memory <= medium_limit) {
set_max_young_space_size(8 * lump_of_memory);
set_max_old_space_size(256 * lump_of_memory);
set_max_executable_size(192 * lump_of_memory);
} else if (physical_memory <= high_limit) {
set_max_young_space_size(16 * lump_of_memory);
set_max_old_space_size(512 * lump_of_memory);
set_max_executable_size(256 * lump_of_memory);
} else {
set_max_young_space_size(16 * lump_of_memory);
set_max_old_space_size(700 * lump_of_memory);
set_max_executable_size(256 * lump_of_memory);
}
set_max_available_threads(i::Max(i::Min(number_of_processors, 4u), 1u));
}
void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory) {
ConfigureDefaults(physical_memory, i::CPU::NumberOfProcessorsOnline());
}
bool SetResourceConstraints(Isolate* v8_isolate,
ResourceConstraints* constraints) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
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<uintptr_t>(constraints->stack_limit());
isolate->stack_guard()->SetStackLimit(limit);
}
isolate->set_max_available_threads(constraints->max_available_threads());
return true;
}
i::Object** V8::GlobalizeReference(i::Isolate* isolate, i::Object** obj) {
LOG_API(isolate, "Persistent::New");
i::Handle<i::Object> result = isolate->global_handles()->Create(*obj);
#ifdef DEBUG
(*obj)->Verify();
#endif // DEBUG
return result.location();
}
i::Object** V8::CopyPersistent(i::Object** obj) {
i::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(obj);
#ifdef DEBUG
(*obj)->Verify();
#endif // DEBUG
return result.location();
}
void V8::MakeWeak(i::Object** object,
void* parameters,
WeakCallback weak_callback,
RevivableCallback weak_reference_callback) {
i::GlobalHandles::MakeWeak(object,
parameters,
weak_callback,
weak_reference_callback);
}
void V8::ClearWeak(i::Object** obj) {
i::GlobalHandles::ClearWeakness(obj);
}
void V8::DisposeGlobal(i::Object** obj) {
i::GlobalHandles::Destroy(obj);
}
void V8::Eternalize(Isolate* v8_isolate, Value* value, int* index) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
i::Object* object = *Utils::OpenHandle(value);
isolate->eternal_handles()->Create(isolate, object, index);
}
Local<Value> V8::GetEternal(Isolate* v8_isolate, int index) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
return Utils::ToLocal(isolate->eternal_handles()->Get(index));
}
// --- H a n d l e s ---
HandleScope::HandleScope(Isolate* isolate) {
Initialize(isolate);
}
void HandleScope::Initialize(Isolate* isolate) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(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::Isolate* isolate, i::Object* value) {
return i::HandleScope::CreateHandle(isolate, value);
}
i::Object** HandleScope::CreateHandle(i::HeapObject* heap_object,
i::Object* value) {
ASSERT(heap_object->IsHeapObject());
return i::HandleScope::CreateHandle(heap_object->GetIsolate(), value);
}
EscapableHandleScope::EscapableHandleScope(Isolate* v8_isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
escape_slot_ = CreateHandle(isolate, isolate->heap()->the_hole_value());
Initialize(v8_isolate);
}
i::Object** EscapableHandleScope::Escape(i::Object** escape_value) {
ApiCheck(*escape_slot_ == isolate_->heap()->the_hole_value(),
"EscapeableHandleScope::Escape",
"Escape value set twice");
if (escape_value == NULL) {
*escape_slot_ = isolate_->heap()->undefined_value();
return NULL;
}
*escape_slot_ = *escape_value;
return escape_slot_;
}
void Context::Enter() {
i::Handle<i::Context> env = Utils::OpenHandle(this);
i::Isolate* isolate = env->GetIsolate();
ENTER_V8(isolate);
isolate->handle_scope_implementer()->EnterContext(env);
isolate->handle_scope_implementer()->SaveContext(isolate->context());
isolate->set_context(*env);
}
void Context::Exit() {
// TODO(dcarney): fix this once chrome is fixed.
i::Isolate* isolate = i::Isolate::Current();
i::Handle<i::Context> context = i::Handle<i::Context>::null();
ENTER_V8(isolate);
if (!ApiCheck(isolate->handle_scope_implementer()->LeaveContext(context),
"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<void*>(value);
}
static i::Smi* EncodeAlignedAsSmi(void* value, const char* location) {
i::Smi* smi = reinterpret_cast<i::Smi*>(value);
ApiCheck(smi->IsSmi(), location, "Pointer is not aligned");
return smi;
}
static i::Handle<i::FixedArray> EmbedderDataFor(Context* context,
int index,
bool can_grow,
const char* location) {
i::Handle<i::Context> env = Utils::OpenHandle(context);
bool ok =
ApiCheck(env->IsNativeContext(), location, "Not a native context") &&
ApiCheck(index >= 0, location, "Negative index");
if (!ok) return i::Handle<i::FixedArray>();
i::Handle<i::FixedArray> data(env->embedder_data());
if (index < data->length()) return data;
if (!can_grow) {
Utils::ReportApiFailure(location, "Index too large");
return i::Handle<i::FixedArray>();
}
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<v8::Value> Context::SlowGetEmbedderData(int index) {
const char* location = "v8::Context::GetEmbedderData()";
i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, false, location);
if (data.is_null()) return Local<Value>();
i::Handle<i::Object> result(data->get(index), data->GetIsolate());
return Utils::ToLocal(result);
}
void Context::SetEmbedderData(int index, v8::Handle<Value> value) {
const char* location = "v8::Context::SetEmbedderData()";
i::Handle<i::FixedArray> data = EmbedderDataFor(this, index, true, location);
if (data.is_null()) return;
i::Handle<i::Object> 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<i::FixedArray> 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<i::FixedArray> 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<i::Object> 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<i::FixedArray> 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<i::Object> value) {
int length = this->length();
int size = obj_.size();
if (length == size - 1) {
i::Factory* factory = i::Isolate::Current()->factory();
i::Handle<i::FixedArray> 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<i::TemplateInfo> that, int type) {
that->set_tag(i::Smi::FromInt(type));
}
static void TemplateSet(i::Isolate* isolate,
v8::Template* templ,
int length,
v8::Handle<v8::Data>* data) {
i::Handle<i::Object> list(Utils::OpenHandle(templ)->property_list(), isolate);
if (list->IsUndefined()) {
list = NeanderArray().value();
Utils::OpenHandle(templ)->set_property_list(*list);
}
NeanderArray array(list);
array.add(Utils::OpenHandle(*v8::Integer::New(length)));
for (int i = 0; i < length; i++) {
i::Handle<i::Object> value = data[i].IsEmpty() ?
i::Handle<i::Object>(isolate->factory()->undefined_value()) :
Utils::OpenHandle(*data[i]);
array.add(value);
}
}
void Template::Set(v8::Handle<String> name,
v8::Handle<Data> value,
v8::PropertyAttribute attribute) {
i::Isolate* isolate = i::Isolate::Current();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
const int kSize = 3;
v8::Handle<v8::Data> data[kSize] = {
name,
value,
v8::Integer::New(attribute)};
TemplateSet(isolate, this, kSize, data);
}
void Template::SetAccessorProperty(
v8::Local<v8::String> name,
v8::Local<FunctionTemplate> getter,
v8::Local<FunctionTemplate> setter,
v8::PropertyAttribute attribute,
v8::AccessControl access_control) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
ASSERT(!name.IsEmpty());
ASSERT(!getter.IsEmpty() || !setter.IsEmpty());
i::HandleScope scope(isolate);
const int kSize = 5;
v8::Handle<v8::Data> data[kSize] = {
name,
getter,
setter,
v8::Integer::New(attribute),
v8::Integer::New(access_control)};
TemplateSet(isolate, this, kSize, data);
}
// --- F u n c t i o n T e m p l a t e ---
static void InitializeFunctionTemplate(
i::Handle<i::FunctionTemplateInfo> info) {
info->set_tag(i::Smi::FromInt(Consts::FUNCTION_TEMPLATE));
info->set_flag(0);
}
Local<ObjectTemplate> FunctionTemplate::PrototypeTemplate() {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::Handle<i::Object> result(Utils::OpenHandle(this)->prototype_template(),
isolate);
if (result->IsUndefined()) {
result = Utils::OpenHandle(*ObjectTemplate::New());
Utils::OpenHandle(this)->set_prototype_template(*result);
}
return ToApiHandle<ObjectTemplate>(result);
}
void FunctionTemplate::Inherit(v8::Handle<FunctionTemplate> value) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
Utils::OpenHandle(this)->set_parent_template(*Utils::OpenHandle(*value));
}
static Local<FunctionTemplate> FunctionTemplateNew(
i::Isolate* isolate,
FunctionCallback callback,
v8::Handle<Value> data,
v8::Handle<Signature> signature,
int length,
bool do_not_cache) {
i::Handle<i::Struct> struct_obj =
isolate->factory()->NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE);
i::Handle<i::FunctionTemplateInfo> obj =
i::Handle<i::FunctionTemplateInfo>::cast(struct_obj);
InitializeFunctionTemplate(obj);
obj->set_do_not_cache(do_not_cache);
int next_serial_number = 0;
if (!do_not_cache) {
next_serial_number = isolate->next_serial_number() + 1;
isolate->set_next_serial_number(next_serial_number);
}
obj->set_serial_number(i::Smi::FromInt(next_serial_number));
if (callback != 0) {
if (data.IsEmpty()) {
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
}
Utils::ToLocal(obj)->SetCallHandler(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> FunctionTemplate::New(
Isolate* isolate,
FunctionCallback callback,
v8::Handle<Value> data,
v8::Handle<Signature> signature,
int length) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
EnsureInitializedForIsolate(i_isolate, "v8::FunctionTemplate::New()");
LOG_API(i_isolate, "FunctionTemplate::New");
ENTER_V8(i_isolate);
return FunctionTemplateNew(
i_isolate, callback, data, signature, length, false);
}
Local<FunctionTemplate> FunctionTemplate::New(
FunctionCallback callback,
v8::Handle<Value> data,
v8::Handle<Signature> signature,
int length) {
return New(Isolate::GetCurrent(), callback, data, signature, length);
}
Local<Signature> Signature::New(Isolate* isolate,
Handle<FunctionTemplate> receiver, int argc,
Handle<FunctionTemplate> argv[]) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
EnsureInitializedForIsolate(i_isolate, "v8::Signature::New()");
LOG_API(i_isolate, "Signature::New");
ENTER_V8(i_isolate);
i::Handle<i::Struct> struct_obj =
i_isolate->factory()->NewStruct(i::SIGNATURE_INFO_TYPE);
i::Handle<i::SignatureInfo> obj =
i::Handle<i::SignatureInfo>::cast(struct_obj);
if (!receiver.IsEmpty()) obj->set_receiver(*Utils::OpenHandle(*receiver));
if (argc > 0) {
i::Handle<i::FixedArray> args = i_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<Signature> Signature::New(Handle<FunctionTemplate> receiver,
int argc, Handle<FunctionTemplate> argv[]) {
return New(Isolate::GetCurrent(), receiver, argc, argv);
}
Local<AccessorSignature> AccessorSignature::New(
Isolate* isolate,
Handle<FunctionTemplate> receiver) {
return Utils::AccessorSignatureToLocal(Utils::OpenHandle(*receiver));
}
// While this is just a cast, it's lame not to use an Isolate parameter.
Local<AccessorSignature> AccessorSignature::New(
Handle<FunctionTemplate> receiver) {
return Utils::AccessorSignatureToLocal(Utils::OpenHandle(*receiver));
}
template<typename Operation>
static Local<Operation> NewDescriptor(
Isolate* isolate,
const i::DeclaredAccessorDescriptorData& data,
Data* previous_descriptor) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
i::Handle<i::DeclaredAccessorDescriptor> previous =
i::Handle<i::DeclaredAccessorDescriptor>();
if (previous_descriptor != NULL) {
previous = Utils::OpenHandle(
static_cast<DeclaredAccessorDescriptor*>(previous_descriptor));
}
i::Handle<i::DeclaredAccessorDescriptor> descriptor =
i::DeclaredAccessorDescriptor::Create(internal_isolate, data, previous);
return Utils::Convert<i::DeclaredAccessorDescriptor, Operation>(descriptor);
}
Local<RawOperationDescriptor>
ObjectOperationDescriptor::NewInternalFieldDereference(
Isolate* isolate,
int internal_field) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorObjectDereference;
data.object_dereference_descriptor.internal_field = internal_field;
return NewDescriptor<RawOperationDescriptor>(isolate, data, NULL);
}
Local<RawOperationDescriptor> 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<RawOperationDescriptor>(isolate, data, this);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewHandleDereference(
Isolate* isolate) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorReturnObject;
return NewDescriptor<DeclaredAccessorDescriptor>(isolate, data, this);
}
Local<RawOperationDescriptor> RawOperationDescriptor::NewRawDereference(
Isolate* isolate) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorPointerDereference;
return NewDescriptor<RawOperationDescriptor>(isolate, data, this);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewPointerCompare(
Isolate* isolate,
void* compare_value) {
i::DeclaredAccessorDescriptorData data;
data.type = i::kDescriptorPointerCompare;
data.pointer_compare_descriptor.compare_value = compare_value;
return NewDescriptor<DeclaredAccessorDescriptor>(isolate, data, this);
}
Local<DeclaredAccessorDescriptor> 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<DeclaredAccessorDescriptor>(isolate, data, this);
}
template<typename T>
static Local<DeclaredAccessorDescriptor> 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<DeclaredAccessorDescriptor>(isolate, data, operation);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewBitmaskCompare8(
Isolate* isolate,
uint8_t bitmask,
uint8_t compare_value) {
return NewBitmaskCompare(isolate, bitmask, compare_value, this);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewBitmaskCompare16(
Isolate* isolate,
uint16_t bitmask,
uint16_t compare_value) {
return NewBitmaskCompare(isolate, bitmask, compare_value, this);
}
Local<DeclaredAccessorDescriptor> RawOperationDescriptor::NewBitmaskCompare32(
Isolate* isolate,
uint32_t bitmask,
uint32_t compare_value) {
return NewBitmaskCompare(isolate, bitmask, compare_value, this);
}
Local<TypeSwitch> TypeSwitch::New(Handle<FunctionTemplate> type) {
Handle<FunctionTemplate> types[1] = { type };
return TypeSwitch::New(1, types);
}
Local<TypeSwitch> TypeSwitch::New(int argc, Handle<FunctionTemplate> types[]) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate, "v8::TypeSwitch::New()");
LOG_API(isolate, "TypeSwitch::New");
ENTER_V8(isolate);
i::Handle<i::FixedArray> vector = isolate->factory()->NewFixedArray(argc);
for (int i = 0; i < argc; i++)
vector->set(i, *Utils::OpenHandle(*types[i]));
i::Handle<i::Struct> struct_obj =
isolate->factory()->NewStruct(i::TYPE_SWITCH_INFO_TYPE);
i::Handle<i::TypeSwitchInfo> obj =
i::Handle<i::TypeSwitchInfo>::cast(struct_obj);
obj->set_types(*vector);
return Utils::ToLocal(obj);
}
int TypeSwitch::match(v8::Handle<Value> value) {
i::Isolate* isolate = i::Isolate::Current();
LOG_API(isolate, "TypeSwitch::match");
USE(isolate);
i::Handle<i::Object> obj = Utils::OpenHandle(*value);
i::Handle<i::TypeSwitchInfo> info = Utils::OpenHandle(this);
i::FixedArray* types = i::FixedArray::cast(info->types());
for (int i = 0; i < types->length(); i++) {
if (i::FunctionTemplateInfo::cast(types->get(i))->IsTemplateFor(*obj))
return i + 1;
}
return 0;
}
#define SET_FIELD_WRAPPED(obj, setter, cdata) do { \
i::Handle<i::Object> foreign = FromCData(obj->GetIsolate(), cdata); \
(obj)->setter(*foreign); \
} while (false)
void FunctionTemplate::SetCallHandler(FunctionCallback callback,
v8::Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::Struct> struct_obj =
isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE);
i::Handle<i::CallHandlerInfo> obj =
i::Handle<i::CallHandlerInfo>::cast(struct_obj);
SET_FIELD_WRAPPED(obj, set_callback, callback);
if (data.IsEmpty()) {
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
}
obj->set_data(*Utils::OpenHandle(*data));
Utils::OpenHandle(this)->set_call_code(*obj);
}
static i::Handle<i::AccessorInfo> SetAccessorInfoProperties(
i::Handle<i::AccessorInfo> obj,
v8::Handle<String> name,
v8::AccessControl settings,
v8::PropertyAttribute attributes,
v8::Handle<AccessorSignature> 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<PropertyAttributes>(attributes));
if (!signature.IsEmpty()) {
obj->set_expected_receiver_type(*Utils::OpenHandle(*signature));
}
return obj;
}
template<typename Getter, typename Setter>
static i::Handle<i::AccessorInfo> MakeAccessorInfo(
v8::Handle<String> name,
Getter getter,
Setter setter,
v8::Handle<Value> data,
v8::AccessControl settings,
v8::PropertyAttribute attributes,
v8::Handle<AccessorSignature> signature) {
i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate();
i::Handle<i::ExecutableAccessorInfo> obj =
isolate->factory()->NewExecutableAccessorInfo();
SET_FIELD_WRAPPED(obj, set_getter, getter);
SET_FIELD_WRAPPED(obj, set_setter, setter);
if (data.IsEmpty()) {
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
}
obj->set_data(*Utils::OpenHandle(*data));
return SetAccessorInfoProperties(obj, name, settings, attributes, signature);
}
static i::Handle<i::AccessorInfo> MakeAccessorInfo(
v8::Handle<String> name,
v8::Handle<v8::DeclaredAccessorDescriptor> descriptor,
void* setter_ignored,
void* data_ignored,
v8::AccessControl settings,
v8::PropertyAttribute attributes,
v8::Handle<AccessorSignature> signature) {
i::Isolate* isolate = Utils::OpenHandle(*name)->GetIsolate();
if (descriptor.IsEmpty()) return i::Handle<i::DeclaredAccessorInfo>();
i::Handle<i::DeclaredAccessorInfo> obj =
isolate->factory()->NewDeclaredAccessorInfo();
obj->set_descriptor(*Utils::OpenHandle(*descriptor));
return SetAccessorInfoProperties(obj, name, settings, attributes, signature);
}
Local<ObjectTemplate> FunctionTemplate::InstanceTemplate() {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
if (EmptyCheck("v8::FunctionTemplate::InstanceTemplate()", this))
return Local<ObjectTemplate>();
ENTER_V8(isolate);
i::Handle<i::FunctionTemplateInfo> handle = Utils::OpenHandle(this);
if (handle->instance_template()->IsUndefined()) {
Local<ObjectTemplate> templ =
ObjectTemplate::New(isolate, ToApiHandle<FunctionTemplate>(handle));
handle->set_instance_template(*Utils::OpenHandle(*templ));
}
i::Handle<i::ObjectTemplateInfo> result(
i::ObjectTemplateInfo::cast(handle->instance_template()));
return Utils::ToLocal(result);
}
void FunctionTemplate::SetLength(int length) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
Utils::OpenHandle(this)->set_length(length);
}
void FunctionTemplate::SetClassName(Handle<String> name) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
Utils::OpenHandle(this)->set_class_name(*Utils::OpenHandle(*name));
}
void FunctionTemplate::SetHiddenPrototype(bool value) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
Utils::OpenHandle(this)->set_hidden_prototype(value);
}
void FunctionTemplate::ReadOnlyPrototype() {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
Utils::OpenHandle(this)->set_read_only_prototype(true);
}
void FunctionTemplate::RemovePrototype() {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
Utils::OpenHandle(this)->set_remove_prototype(true);
}
// --- O b j e c t T e m p l a t e ---
Local<ObjectTemplate> ObjectTemplate::New(Isolate* isolate) {
return New(reinterpret_cast<i::Isolate*>(isolate), Local<FunctionTemplate>());
}
Local<ObjectTemplate> ObjectTemplate::New() {
return New(i::Isolate::Current(), Local<FunctionTemplate>());
}
Local<ObjectTemplate> ObjectTemplate::New(
i::Isolate* isolate,
v8::Handle<FunctionTemplate> constructor) {
EnsureInitializedForIsolate(isolate, "v8::ObjectTemplate::New()");
LOG_API(isolate, "ObjectTemplate::New");
ENTER_V8(isolate);
i::Handle<i::Struct> struct_obj =
isolate->factory()->NewStruct(i::OBJECT_TEMPLATE_INFO_TYPE);
i::Handle<i::ObjectTemplateInfo> obj =
i::Handle<i::ObjectTemplateInfo>::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 i::Handle<i::FunctionTemplateInfo> EnsureConstructor(
ObjectTemplate* object_template) {
i::Object* obj = Utils::OpenHandle(object_template)->constructor();
if (!obj ->IsUndefined()) {
i::FunctionTemplateInfo* info = i::FunctionTemplateInfo::cast(obj);
return i::Handle<i::FunctionTemplateInfo>(info, info->GetIsolate());
}
Local<FunctionTemplate> templ = FunctionTemplate::New();
i::Handle<i::FunctionTemplateInfo> constructor = Utils::OpenHandle(*templ);
constructor->set_instance_template(*Utils::OpenHandle(object_template));
Utils::OpenHandle(object_template)->set_constructor(*constructor);
return constructor;
}
static inline void AddPropertyToTemplate(
i::Handle<i::TemplateInfo> info,
i::Handle<i::AccessorInfo> obj) {
i::Handle<i::Object> list(info->property_accessors(), info->GetIsolate());
if (list->IsUndefined()) {
list = NeanderArray().value();
info->set_property_accessors(*list);
}
NeanderArray array(list);
array.add(obj);
}
static inline i::Handle<i::TemplateInfo> GetTemplateInfo(
Template* template_obj) {
return Utils::OpenHandle(template_obj);
}
// TODO(dcarney): remove this with ObjectTemplate::SetAccessor
static inline i::Handle<i::TemplateInfo> GetTemplateInfo(
ObjectTemplate* object_template) {
EnsureConstructor(object_template);
return Utils::OpenHandle(object_template);
}
template<typename Setter, typename Getter, typename Data, typename Template>
static bool TemplateSetAccessor(
Template* template_obj,
v8::Local<String> name,
Getter getter,
Setter setter,
Data data,
AccessControl settings,
PropertyAttribute attribute,
v8::Local<AccessorSignature> signature) {
i::Isolate* isolate = Utils::OpenHandle(template_obj)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::AccessorInfo> obj = MakeAccessorInfo(
name, getter, setter, data, settings, attribute, signature);
if (obj.is_null()) return false;
i::Handle<i::TemplateInfo> info = GetTemplateInfo(template_obj);
AddPropertyToTemplate(info, obj);
return true;
}
bool Template::SetDeclaredAccessor(
Local<String> name,
Local<DeclaredAccessorDescriptor> descriptor,
PropertyAttribute attribute,
Local<AccessorSignature> signature,
AccessControl settings) {
void* null = NULL;
return TemplateSetAccessor(
this, name, descriptor, null, null, settings, attribute, signature);
}
void Template::SetNativeDataProperty(v8::Local<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter,
v8::Handle<Value> data,
PropertyAttribute attribute,
v8::Local<AccessorSignature> signature,
AccessControl settings) {
TemplateSetAccessor(
this, name, getter, setter, data, settings, attribute, signature);
}
void ObjectTemplate::SetAccessor(v8::Handle<String> name,
AccessorGetterCallback getter,
AccessorSetterCallback setter,
v8::Handle<Value> data,
AccessControl settings,
PropertyAttribute attribute,
v8::Handle<AccessorSignature> signature) {
TemplateSetAccessor(
this, name, getter, setter, data, settings, attribute, signature);
}
void ObjectTemplate::SetNamedPropertyHandler(
NamedPropertyGetterCallback getter,
NamedPropertySetterCallback setter,
NamedPropertyQueryCallback query,
NamedPropertyDeleterCallback remover,
NamedPropertyEnumeratorCallback enumerator,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
i::Handle<i::Struct> struct_obj =
isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE);
i::Handle<i::InterceptorInfo> obj =
i::Handle<i::InterceptorInfo>::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(reinterpret_cast<v8::Isolate*>(isolate));
}
obj->set_data(*Utils::OpenHandle(*data));
cons->set_named_property_handler(*obj);
}
void ObjectTemplate::MarkAsUndetectable() {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
cons->set_undetectable(true);
}
void ObjectTemplate::SetAccessCheckCallbacks(
NamedSecurityCallback named_callback,
IndexedSecurityCallback indexed_callback,
Handle<Value> data,
bool turned_on_by_default) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::Handle<i::Struct> struct_info =
isolate->factory()->NewStruct(i::ACCESS_CHECK_INFO_TYPE);
i::Handle<i::AccessCheckInfo> info =
i::Handle<i::AccessCheckInfo>::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(reinterpret_cast<v8::Isolate*>(isolate));
}
info->set_data(*Utils::OpenHandle(*data));
i::FunctionTemplateInfo* constructor =
i::FunctionTemplateInfo::cast(Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
cons->set_access_check_info(*info);
cons->set_needs_access_check(turned_on_by_default);
}
void ObjectTemplate::SetIndexedPropertyHandler(
IndexedPropertyGetterCallback getter,
IndexedPropertySetterCallback setter,
IndexedPropertyQueryCallback query,
IndexedPropertyDeleterCallback remover,
IndexedPropertyEnumeratorCallback enumerator,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
i::Handle<i::Struct> struct_obj =
isolate->factory()->NewStruct(i::INTERCEPTOR_INFO_TYPE);
i::Handle<i::InterceptorInfo> obj =
i::Handle<i::InterceptorInfo>::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(reinterpret_cast<v8::Isolate*>(isolate));
}
obj->set_data(*Utils::OpenHandle(*data));
cons->set_indexed_property_handler(*obj);
}
void ObjectTemplate::SetCallAsFunctionHandler(FunctionCallback callback,
Handle<Value> data) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EnsureConstructor(this);
i::FunctionTemplateInfo* constructor = i::FunctionTemplateInfo::cast(
Utils::OpenHandle(this)->constructor());
i::Handle<i::FunctionTemplateInfo> cons(constructor);
i::Handle<i::Struct> struct_obj =
isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE);
i::Handle<i::CallHandlerInfo> obj =
i::Handle<i::CallHandlerInfo>::cast(struct_obj);
SET_FIELD_WRAPPED(obj, set_callback, callback);
if (data.IsEmpty()) {
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
}
obj->set_data(*Utils::OpenHandle(*data));
cons->set_instance_call_handler(*obj);
}
int ObjectTemplate::InternalFieldCount() {
return i::Smi::cast(Utils::OpenHandle(this)->internal_field_count())->value();
}
void ObjectTemplate::SetInternalFieldCount(int value) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
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(v8::Isolate* isolate,
const char* input,
int length) {
i::Utf8ToUtf16CharacterStream stream(
reinterpret_cast<const unsigned char*>(input), length);
return i::PreParserApi::PreParse(
reinterpret_cast<i::Isolate*>(isolate), &stream);
}
ScriptData* ScriptData::PreCompile(v8::Handle<String> source) {
i::Handle<i::String> str = Utils::OpenHandle(*source);
i::Isolate* isolate = str->GetIsolate();
if (str->IsExternalTwoByteString()) {
i::ExternalTwoByteStringUtf16CharacterStream stream(
i::Handle<i::ExternalTwoByteString>::cast(str), 0, str->length());
return i::PreParserApi::PreParse(isolate, &stream);
} else {
i::GenericStringUtf16CharacterStream stream(str, 0, str->length());
return i::PreParserApi::PreParse(isolate, &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<intptr_t>(data) % sizeof(unsigned) == 0) {
return new i::ScriptDataImpl(data, length);
}
// Copy the data to align it.
unsigned* deserialized_data = i::NewArray<unsigned>(deserialized_data_length);
i::CopyBytes(reinterpret_cast<char*>(deserialized_data),
data, static_cast<size_t>(length));
return new i::ScriptDataImpl(
i::Vector<unsigned>(deserialized_data, deserialized_data_length));
}
// --- S c r i p t ---
Local<Script> Script::New(v8::Handle<String> source,
v8::ScriptOrigin* origin,
v8::ScriptData* pre_data,
v8::Handle<String> script_data) {
i::Handle<i::String> str = Utils::OpenHandle(*source);
i::Isolate* isolate = str->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::New()", return Local<Script>());
LOG_API(isolate, "Script::New");
ENTER_V8(isolate);
i::SharedFunctionInfo* raw_result = NULL;
{ i::HandleScope scope(isolate);
i::Handle<i::Object> name_obj;
int line_offset = 0;
int column_offset = 0;
bool is_shared_cross_origin = false;
if (origin != NULL) {
if (!origin->ResourceName().IsEmpty()) {
name_obj = Utils::OpenHandle(*origin->ResourceName());
}
if (!origin->ResourceLineOffset().IsEmpty()) {
line_offset = static_cast<int>(origin->ResourceLineOffset()->Value());
}
if (!origin->ResourceColumnOffset().IsEmpty()) {
column_offset =
static_cast<int>(origin->ResourceColumnOffset()->Value());
}
if (!origin->ResourceIsSharedCrossOrigin().IsEmpty()) {
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
is_shared_cross_origin =
origin->ResourceIsSharedCrossOrigin() == v8::True(v8_isolate);
}
}
EXCEPTION_PREAMBLE(isolate);
i::ScriptDataImpl* pre_data_impl =
static_cast<i::ScriptDataImpl*>(pre_data);
// We assert that the pre-data is sane, even though we can actually
// handle it if it turns out not to be in release mode.
ASSERT(pre_data_impl == NULL || pre_data_impl->SanityCheck());
// If the pre-data isn't sane we simply ignore it
if (pre_data_impl != NULL && !pre_data_impl->SanityCheck()) {
pre_data_impl = NULL;
}
i::Handle<i::SharedFunctionInfo> result =
i::Compiler::Compile(str,
name_obj,
line_offset,
column_offset,
is_shared_cross_origin,
isolate->global_context(),
NULL,
pre_data_impl,
Utils::OpenHandle(*script_data, true),
i::NOT_NATIVES_CODE);
has_pending_exception = result.is_null();
EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>());
raw_result = *result;
}
i::Handle<i::SharedFunctionInfo> result(raw_result, isolate);
return ToApiHandle<Script>(result);
}
Local<Script> Script::New(v8::Handle<String> source,
v8::Handle<Value> file_name) {
ScriptOrigin origin(file_name);
return New(source, &origin);
}
Local<Script> Script::Compile(v8::Handle<String> source,
v8::ScriptOrigin* origin,
v8::ScriptData* pre_data,
v8::Handle<String> script_data) {
i::Handle<i::String> str = Utils::OpenHandle(*source);
i::Isolate* isolate = str->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::Compile()", return Local<Script>());
LOG_API(isolate, "Script::Compile");
ENTER_V8(isolate);
Local<Script> generic = New(source, origin, pre_data, script_data);
if (generic.IsEmpty())
return generic;
i::Handle<i::Object> obj = Utils::OpenHandle(*generic);
i::Handle<i::SharedFunctionInfo> function =
i::Handle<i::SharedFunctionInfo>(i::SharedFunctionInfo::cast(*obj));
i::Handle<i::JSFunction> result =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
function,
isolate->global_context());
return ToApiHandle<Script>(result);
}
Local<Script> Script::Compile(v8::Handle<String> source,
v8::Handle<Value> file_name,
v8::Handle<String> script_data) {
ScriptOrigin origin(file_name);
return Compile(source, &origin, 0, script_data);
}
Local<Value> Script::Run() {
// If execution is terminating, Compile(script)->Run() requires this check.
if (this == NULL) return Local<Value>();
i::Handle<i::HeapObject> obj =
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>());
LOG_API(isolate, "Script::Run");
ENTER_V8(isolate);
i::Logger::TimerEventScope timer_scope(
isolate, i::Logger::TimerEventScope::v8_execute);
i::Object* raw_result = NULL;
{
i::HandleScope scope(isolate);
i::Handle<i::JSFunction> fun;
if (obj->IsSharedFunctionInfo()) {
i::Handle<i::SharedFunctionInfo>
function_info(i::SharedFunctionInfo::cast(*obj), isolate);
fun = isolate->factory()->NewFunctionFromSharedFunctionInfo(
function_info, isolate->global_context());
} else {
fun = i::Handle<i::JSFunction>(i::JSFunction::cast(*obj), isolate);
}
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> receiver(
isolate->context()->global_proxy(), isolate);
i::Handle<i::Object> result = i::Execution::Call(
isolate, fun, receiver, 0, NULL, &has_pending_exception);
EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Value>());
raw_result = *result;
}
i::Handle<i::Object> result(raw_result, isolate);
return Utils::ToLocal(result);
}
static i::Handle<i::SharedFunctionInfo> OpenScript(Script* script) {
i::Handle<i::Object> obj = Utils::OpenHandle(script);
i::Handle<i::SharedFunctionInfo> result;
if (obj->IsSharedFunctionInfo()) {
result =
i::Handle<i::SharedFunctionInfo>(i::SharedFunctionInfo::cast(*obj));
} else {
result =
i::Handle<i::SharedFunctionInfo>(i::JSFunction::cast(*obj)->shared());
}
return result;
}
Local<Value> Script::Id() {
i::Handle<i::HeapObject> obj =
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::Id()", return Local<Value>());
LOG_API(isolate, "Script::Id");
i::Object* raw_id = NULL;
{
i::HandleScope scope(isolate);
i::Handle<i::SharedFunctionInfo> function_info = OpenScript(this);
i::Handle<i::Script> script(i::Script::cast(function_info->script()));
i::Handle<i::Object> id(script->id(), isolate);
raw_id = *id;
}
i::Handle<i::Object> id(raw_id, isolate);
return Utils::ToLocal(id);
}
int Script::GetId() {
i::Handle<i::HeapObject> obj =
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::Id()", return -1);
LOG_API(isolate, "Script::Id");
{
i::HandleScope scope(isolate);
i::Handle<i::SharedFunctionInfo> function_info = OpenScript(this);
i::Handle<i::Script> script(i::Script::cast(function_info->script()));
return script->id()->value();
}
}
int Script::GetLineNumber(int code_pos) {
i::Handle<i::HeapObject> obj =
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::GetLineNumber()", return -1);
LOG_API(isolate, "Script::GetLineNumber");
if (obj->IsScript()) {
i::Handle<i::Script> script = i::Handle<i::Script>(i::Script::cast(*obj));
return i::GetScriptLineNumber(script, code_pos);
} else {
return -1;
}
}
Handle<Value> Script::GetScriptName() {
i::Handle<i::HeapObject> obj =
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::GetName()", return Handle<String>());
LOG_API(isolate, "Script::GetName");
if (obj->IsScript()) {
i::Object* name = i::Script::cast(*obj)->name();
return Utils::ToLocal(i::Handle<i::Object>(name, isolate));
} else {
return Handle<String>();
}
}
void Script::SetData(v8::Handle<String> data) {
i::Handle<i::HeapObject> obj =
i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
i::Isolate* isolate = obj->GetIsolate();
ON_BAILOUT(isolate, "v8::Script::SetData()", return);
LOG_API(isolate, "Script::SetData");
{
i::HandleScope scope(isolate);
i::Handle<i::SharedFunctionInfo> function_info = OpenScript(this);
i::Handle<i::Object> raw_data = Utils::OpenHandle(*data);
i::Handle<i::Script> script(i::Script::cast(function_info->script()));
script->set_data(*raw_data);
}
}
// --- E x c e p t i o n s ---
v8::TryCatch::TryCatch()
: isolate_(i::Isolate::Current()),
next_(isolate_->try_catch_handler_address()),
is_verbose_(false),
can_continue_(true),
capture_message_(true),
rethrow_(false),
has_terminated_(false) {
Reset();
isolate_->RegisterTryCatchHandler(this);
}
v8::TryCatch::~TryCatch() {
ASSERT(isolate_ == i::Isolate::Current());
if (rethrow_) {
v8::Isolate* isolate = reinterpret_cast<Isolate*>(isolate_);
v8::HandleScope scope(isolate);
v8::Local<v8::Value> exc = v8::Local<v8::Value>::New(isolate, Exception());
if (HasCaught() && capture_message_) {
// If an exception was caught and rethrow_ is indicated, the saved
// message, script, and location need to be restored to Isolate TLS
// for reuse. capture_message_ needs to be disabled so that DoThrow()
// does not create a new message.
isolate_->thread_local_top()->rethrowing_message_ = true;
isolate_->RestorePendingMessageFromTryCatch(this);
}
isolate_->UnregisterTryCatchHandler(this);
reinterpret_cast<Isolate*>(isolate_)->ThrowException(exc);
ASSERT(!isolate_->thread_local_top()->rethrowing_message_);
} else {
isolate_->UnregisterTryCatchHandler(this);
}
}
bool v8::TryCatch::HasCaught() const {
return !reinterpret_cast<i::Object*>(exception_)->IsTheHole();
}
bool v8::TryCatch::CanContinue() const {
return can_continue_;
}
bool v8::TryCatch::HasTerminated() const {
return has_terminated_;
}
v8::Handle<v8::Value> v8::TryCatch::ReThrow() {
if (!HasCaught()) return v8::Local<v8::Value>();
rethrow_ = true;
return v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate_));
}
v8::Local<Value> v8::TryCatch::Exception() const {
ASSERT(isolate_ == i::Isolate::Current());
if (HasCaught()) {
// Check for out of memory exception.
i::Object* exception = reinterpret_cast<i::Object*>(exception_);
return v8::Utils::ToLocal(i::Handle<i::Object>(exception, isolate_));
} else {
return v8::Local<Value>();
}
}
v8::Local<Value> v8::TryCatch::StackTrace() const {
ASSERT(isolate_ == i::Isolate::Current());
if (HasCaught()) {
i::Object* raw_obj = reinterpret_cast<i::Object*>(exception_);
if (!raw_obj->IsJSObject()) return v8::Local<Value>();
i::HandleScope scope(isolate_);
i::Handle<i::JSObject> obj(i::JSObject::cast(raw_obj), isolate_);
i::Handle<i::String> name = isolate_->factory()->stack_string();
if (!i::JSReceiver::HasProperty(obj, name)) return v8::Local<Value>();
i::Handle<i::Object> value = i::GetProperty(isolate_, obj, name);
if (value.is_null()) return v8::Local<Value>();
return v8::Utils::ToLocal(scope.CloseAndEscape(value));
} else {
return v8::Local<Value>();
}
}
v8::Local<v8::Message> v8::TryCatch::Message() const {
ASSERT(isolate_ == i::Isolate::Current());
i::Object* message = reinterpret_cast<i::Object*>(message_obj_);
ASSERT(message->IsJSMessageObject() || message->IsTheHole());
if (HasCaught() && !message->IsTheHole()) {
return v8::Utils::MessageToLocal(i::Handle<i::Object>(message, isolate_));
} else {
return v8::Local<v8::Message>();
}
}
void v8::TryCatch::Reset() {
ASSERT(isolate_ == i::Isolate::Current());
i::Object* the_hole = isolate_->heap()->the_hole_value();
exception_ = the_hole;
message_obj_ = the_hole;
message_script_ = the_hole;
message_start_pos_ = 0;
message_end_pos_ = 0;
}
void v8::TryCatch::SetVerbose(bool value) {
is_verbose_ = value;
}
void v8::TryCatch::SetCaptureMessage(bool value) {
capture_message_ = value;
}
// --- M e s s a g e ---
Local<String> Message::Get() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Message::Get()", return Local<String>());
ENTER_V8(isolate);
EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::Object> obj = Utils::OpenHandle(this);
i::Handle<i::String> raw_result = i::MessageHandler::GetMessage(isolate, obj);
Local<String> result = Utils::ToLocal(raw_result);
return scope.Escape(result);
}
v8::Handle<Value> Message::GetScriptResourceName() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
// Return this.script.name.
i::Handle<i::JSValue> script =
i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script(),
isolate));
i::Handle<i::Object> resource_name(i::Script::cast(script->value())->name(),
isolate);
return scope.Escape(Utils::ToLocal(resource_name));
}
v8::Handle<Value> Message::GetScriptData() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
// Return this.script.data.
i::Handle<i::JSValue> script =
i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script(),
isolate));
i::Handle<i::Object> data(i::Script::cast(script->value())->data(), isolate);
return scope.Escape(Utils::ToLocal(data));
}
v8::Handle<v8::StackTrace> Message::GetStackTrace() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
i::Handle<i::Object> stackFramesObj(message->stack_frames(), isolate);
if (!stackFramesObj->IsJSArray()) return v8::Handle<v8::StackTrace>();
i::Handle<i::JSArray> stackTrace =
i::Handle<i::JSArray>::cast(stackFramesObj);
return scope.Escape(Utils::StackTraceToLocal(stackTrace));
}
static i::Handle<i::Object> CallV8HeapFunction(const char* name,
i::Handle<i::Object> recv,
int argc,
i::Handle<i::Object> argv[],
bool* has_pending_exception) {
i::Isolate* isolate = i::Isolate::Current();
i::Handle<i::String> fmt_str =
isolate->factory()->InternalizeUtf8String(name);
i::Object* object_fun =
isolate->js_builtins_object()->GetPropertyNoExceptionThrown(*fmt_str);
i::Handle<i::JSFunction> fun =
i::Handle<i::JSFunction>(i::JSFunction::cast(object_fun));
i::Handle<i::Object> value = i::Execution::Call(
isolate, fun, recv, argc, argv, has_pending_exception);
return value;
}
static i::Handle<i::Object> CallV8HeapFunction(const char* name,
i::Handle<i::Object> data,
bool* has_pending_exception) {
i::Handle<i::Object> argv[] = { data };
return CallV8HeapFunction(name,
i::Isolate::Current()->js_builtins_object(),
ARRAY_SIZE(argv),
argv,
has_pending_exception);
}
int Message::GetLineNumber() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Message::GetLineNumber()", return kNoLineNumberInfo);
ENTER_V8(isolate);
i::HandleScope scope(isolate);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = CallV8HeapFunction("GetLineNumber",
Utils::OpenHandle(this),
&has_pending_exception);
EXCEPTION_BAILOUT_CHECK(isolate, 0);
return static_cast<int>(result->Number());
}
int Message::GetStartPosition() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
return message->start_position();
}
int Message::GetEndPosition() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
return message->end_position();
}
int Message::GetStartColumn() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
"GetPositionInLine",
data_obj,
&has_pending_exception);
EXCEPTION_BAILOUT_CHECK(isolate, 0);
return static_cast<int>(start_col_obj->Number());
}
int Message::GetEndColumn() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> data_obj = Utils::OpenHandle(this);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> start_col_obj = CallV8HeapFunction(
"GetPositionInLine",
data_obj,
&has_pending_exception);
EXCEPTION_BAILOUT_CHECK(isolate, 0);
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(data_obj);
int start = message->start_position();
int end = message->end_position();
return static_cast<int>(start_col_obj->Number()) + (end - start);
}
bool Message::IsSharedCrossOrigin() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSMessageObject> message =
i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this));
i::Handle<i::JSValue> script =
i::Handle<i::JSValue>::cast(i::Handle<i::Object>(message->script(),
isolate));
return i::Script::cast(script->value())->is_shared_cross_origin();
}
Local<String> Message::GetSourceLine() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Message::GetSourceLine()", return Local<String>());
ENTER_V8(isolate);
EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> result = CallV8HeapFunction("GetSourceLine",
Utils::OpenHandle(this),
&has_pending_exception);
EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::String>());
if (result->IsString()) {
return scope.Escape(Utils::ToLocal(i::Handle<i::String>::cast(result)));
} else {
return Local<String>();
}
}
void Message::PrintCurrentStackTrace(Isolate* isolate, FILE* out) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ENTER_V8(i_isolate);
i_isolate->PrintCurrentStackTrace(out);
}
void Message::PrintCurrentStackTrace(FILE* out) {
PrintCurrentStackTrace(Isolate::GetCurrent(), out);
}
// --- S t a c k T r a c e ---
Local<StackFrame> StackTrace::GetFrame(uint32_t index) const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::JSArray> self = Utils::OpenHandle(this);
i::Object* raw_object = self->GetElementNoExceptionThrown(isolate, index);
i::Handle<i::JSObject> obj(i::JSObject::cast(raw_object));
return scope.Escape(Utils::StackFrameToLocal(obj));
}
int StackTrace::GetFrameCount() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
return i::Smi::cast(Utils::OpenHandle(this)->length())->value();
}
Local<Array> StackTrace::AsArray() {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
return Utils::ToLocal(Utils::OpenHandle(this));
}
Local<StackTrace> StackTrace::CurrentStackTrace(
Isolate* isolate,
int frame_limit,
StackTraceOptions options) {
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
ENTER_V8(i_isolate);
i::Handle<i::JSArray> stackTrace =
i_isolate->CaptureCurrentStackTrace(frame_limit, options);
return Utils::StackTraceToLocal(stackTrace);
}
Local<StackTrace> StackTrace::CurrentStackTrace(int frame_limit,
StackTraceOptions options) {
return CurrentStackTrace(Isolate::GetCurrent(), frame_limit, options);
}
// --- S t a c k F r a m e ---
int StackFrame::GetLineNumber() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> line = GetProperty(self, "lineNumber");
if (!line->IsSmi()) {
return Message::kNoLineNumberInfo;
}
return i::Smi::cast(*line)->value();
}
int StackFrame::GetColumn() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> column = GetProperty(self, "column");
if (!column->IsSmi()) {
return Message::kNoColumnInfo;
}
return i::Smi::cast(*column)->value();
}
int StackFrame::GetScriptId() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
i::HandleScope scope(isolate);
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> scriptId = GetProperty(self, "scriptId");
if (!scriptId->IsSmi()) {
return Message::kNoScriptIdInfo;
}
return i::Smi::cast(*scriptId)->value();
}
Local<String> StackFrame::GetScriptName() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> name = GetProperty(self, "scriptName");
if (!name->IsString()) {
return Local<String>();
}
return scope.Escape(Local<String>::Cast(Utils::ToLocal(name)));
}
Local<String> StackFrame::GetScriptNameOrSourceURL() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::Object> name = GetProperty(self, "scriptNameOrSourceURL");
if (!name->IsString()) {
return Local<String>();
}
return scope.Escape(Local<String>::Cast(Utils::ToLocal(name)));
}
Local<String> StackFrame::GetFunctionName() const {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ENTER_V8(isolate);
EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate));
i::Handle<i::JSObject> self = Utils::OpenHandle(this);
i::Handle<i::