| // Copyright 2012 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/api.h" |
| |
| #include <string.h> // For memcpy, strlen. |
| #ifdef V8_USE_ADDRESS_SANITIZER |
| #include <sanitizer/asan_interface.h> |
| #endif // V8_USE_ADDRESS_SANITIZER |
| #include <cmath> // For isnan. |
| #include "include/v8-debug.h" |
| #include "include/v8-profiler.h" |
| #include "include/v8-testing.h" |
| #include "src/assert-scope.h" |
| #include "src/background-parsing-task.h" |
| #include "src/base/platform/platform.h" |
| #include "src/base/platform/time.h" |
| #include "src/base/utils/random-number-generator.h" |
| #include "src/bootstrapper.h" |
| #include "src/code-stubs.h" |
| #include "src/compiler.h" |
| #include "src/conversions-inl.h" |
| #include "src/counters.h" |
| #include "src/cpu-profiler.h" |
| #include "src/debug.h" |
| #include "src/deoptimizer.h" |
| #include "src/execution.h" |
| #include "src/global-handles.h" |
| #include "src/heap-profiler.h" |
| #include "src/heap-snapshot-generator-inl.h" |
| #include "src/icu_util.h" |
| #include "src/json-parser.h" |
| #include "src/messages.h" |
| #include "src/natives.h" |
| #include "src/parser.h" |
| #include "src/profile-generator-inl.h" |
| #include "src/property.h" |
| #include "src/property-details.h" |
| #include "src/prototype.h" |
| #include "src/runtime/runtime.h" |
| #include "src/runtime-profiler.h" |
| #include "src/sampler.h" |
| #include "src/scanner-character-streams.h" |
| #include "src/simulator.h" |
| #include "src/snapshot.h" |
| #include "src/unicode-inl.h" |
| #include "src/v8threads.h" |
| #include "src/version.h" |
| #include "src/vm-state-inl.h" |
| |
| |
| #define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr)) |
| |
| #define ENTER_V8(isolate) \ |
| i::VMState<v8::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(); \ |
| DCHECK(!(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) { \ |
| 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, isolate->FireCallCompletedCallback();) |
| |
| |
| #define EXCEPTION_BAILOUT_CHECK(isolate, value) \ |
| EXCEPTION_BAILOUT_CHECK_GENERIC(isolate, value, ;) |
| |
| |
| // --- E x c e p t i o n B e h a v i o r --- |
| |
| |
| 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); |
| } |
| Utils::ApiCheck(false, location, "Allocation failed - process out of memory"); |
| // If the fatal error handler returns, we stop execution. |
| FATAL("API fatal error handler returned after process out of memory"); |
| } |
| |
| |
| void Utils::ReportApiFailure(const char* location, const char* message) { |
| i::Isolate* isolate = i::Isolate::Current(); |
| FatalErrorCallback callback = isolate->exception_behavior(); |
| if (callback == NULL) { |
| base::OS::PrintError("\n#\n# Fatal error in %s\n# %s\n#\n\n", location, |
| message); |
| base::OS::Abort(); |
| } else { |
| callback(location, message); |
| } |
| isolate->SignalFatalError(); |
| } |
| |
| |
| static inline bool IsExecutionTerminatingCheck(i::Isolate* isolate) { |
| if (isolate->has_scheduled_exception()) { |
| return isolate->scheduled_exception() == |
| isolate->heap()->termination_exception(); |
| } |
| return false; |
| } |
| |
| |
| 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 { |
| DCHECK_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 |
| DCHECK_EQ(i::Snapshot::raw_size(), decompressed_data[kSnapshot].raw_size); |
| i::Snapshot::set_raw_data( |
| reinterpret_cast<const i::byte*>(decompressed_data[kSnapshot].data)); |
| |
| DCHECK_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)); |
| |
| DCHECK_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); |
| |
| DCHECK_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::SetNativesDataBlob(StartupData* natives_blob) { |
| #ifdef V8_USE_EXTERNAL_STARTUP_DATA |
| i::SetNativesFromFile(natives_blob); |
| #else |
| CHECK(false); |
| #endif |
| } |
| |
| |
| void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) { |
| #ifdef V8_USE_EXTERNAL_STARTUP_DATA |
| i::SetSnapshotFromFile(snapshot_blob); |
| #else |
| CHECK(false); |
| #endif |
| } |
| |
| |
| void V8::SetFlagsFromString(const char* str, int length) { |
| i::FlagList::SetFlagsFromString(str, length); |
| } |
| |
| |
| void V8::SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags) { |
| i::FlagList::SetFlagsFromCommandLine(argc, argv, remove_flags); |
| } |
| |
| |
| 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; |
| } |
| first_extension_ = NULL; |
| } |
| |
| |
| 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); |
| } |
| |
| |
| ResourceConstraints::ResourceConstraints() |
| : max_semi_space_size_(0), |
| max_old_space_size_(0), |
| max_executable_size_(0), |
| stack_limit_(NULL), |
| max_available_threads_(0), |
| code_range_size_(0) { } |
| |
| void ResourceConstraints::ConfigureDefaults(uint64_t physical_memory, |
| uint64_t virtual_memory_limit, |
| uint32_t number_of_processors) { |
| #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 |
| |
| if (physical_memory <= low_limit) { |
| set_max_semi_space_size(i::Heap::kMaxSemiSpaceSizeLowMemoryDevice); |
| set_max_old_space_size(i::Heap::kMaxOldSpaceSizeLowMemoryDevice); |
| set_max_executable_size(i::Heap::kMaxExecutableSizeLowMemoryDevice); |
| } else if (physical_memory <= medium_limit) { |
| set_max_semi_space_size(i::Heap::kMaxSemiSpaceSizeMediumMemoryDevice); |
| set_max_old_space_size(i::Heap::kMaxOldSpaceSizeMediumMemoryDevice); |
| set_max_executable_size(i::Heap::kMaxExecutableSizeMediumMemoryDevice); |
| } else if (physical_memory <= high_limit) { |
| set_max_semi_space_size(i::Heap::kMaxSemiSpaceSizeHighMemoryDevice); |
| set_max_old_space_size(i::Heap::kMaxOldSpaceSizeHighMemoryDevice); |
| set_max_executable_size(i::Heap::kMaxExecutableSizeHighMemoryDevice); |
| } else { |
| set_max_semi_space_size(i::Heap::kMaxSemiSpaceSizeHugeMemoryDevice); |
| set_max_old_space_size(i::Heap::kMaxOldSpaceSizeHugeMemoryDevice); |
| set_max_executable_size(i::Heap::kMaxExecutableSizeHugeMemoryDevice); |
| } |
| |
| set_max_available_threads(i::Max(i::Min(number_of_processors, 4u), 1u)); |
| |
| if (virtual_memory_limit > 0 && i::kRequiresCodeRange) { |
| // Reserve no more than 1/8 of the memory for the code range, but at most |
| // kMaximalCodeRangeSize. |
| set_code_range_size( |
| i::Min(i::kMaximalCodeRangeSize / i::MB, |
| static_cast<size_t>((virtual_memory_limit >> 3) / i::MB))); |
| } |
| } |
| |
| |
| void SetResourceConstraints(i::Isolate* isolate, |
| const ResourceConstraints& constraints) { |
| int semi_space_size = constraints.max_semi_space_size(); |
| int old_space_size = constraints.max_old_space_size(); |
| int max_executable_size = constraints.max_executable_size(); |
| size_t code_range_size = constraints.code_range_size(); |
| if (semi_space_size != 0 || old_space_size != 0 || |
| max_executable_size != 0 || code_range_size != 0) { |
| isolate->heap()->ConfigureHeap(semi_space_size, old_space_size, |
| max_executable_size, code_range_size); |
| } |
| 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()); |
| } |
| |
| |
| 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)->ObjectVerify(); |
| #endif // DEBUG |
| return result.location(); |
| } |
| |
| |
| i::Object** V8::CopyPersistent(i::Object** obj) { |
| i::Handle<i::Object> result = i::GlobalHandles::CopyGlobal(obj); |
| #ifdef DEBUG |
| (*obj)->ObjectVerify(); |
| #endif // DEBUG |
| return result.location(); |
| } |
| |
| |
| void V8::MakeWeak(i::Object** object, void* parameters, |
| WeakCallback weak_callback, V8::WeakHandleType weak_type) { |
| i::GlobalHandles::PhantomState phantom; |
| phantom = weak_type == V8::PhantomHandle ? i::GlobalHandles::Phantom |
| : i::GlobalHandles::Nonphantom; |
| i::GlobalHandles::MakeWeak(object, parameters, weak_callback, phantom); |
| } |
| |
| |
| void* V8::ClearWeak(i::Object** obj) { |
| return 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); |
| // We do not want to check the correct usage of the Locker class all over the |
| // place, so we do it only here: Without a HandleScope, an embedder can do |
| // almost nothing, so it is enough to check in this central place. |
| Utils::ApiCheck(!v8::Locker::IsActive() || |
| internal_isolate->thread_manager()->IsLockedByCurrentThread(), |
| "HandleScope::HandleScope", |
| "Entering the V8 API without proper locking in place"); |
| i::HandleScopeData* current = internal_isolate->handle_scope_data(); |
| isolate_ = internal_isolate; |
| prev_next_ = current->next; |
| prev_limit_ = current->limit; |
| current->level++; |
| } |
| |
| |
| HandleScope::~HandleScope() { |
| i::HandleScope::CloseScope(isolate_, prev_next_, prev_limit_); |
| } |
| |
| |
| int HandleScope::NumberOfHandles(Isolate* isolate) { |
| return i::HandleScope::NumberOfHandles( |
| reinterpret_cast<i::Isolate*>(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) { |
| DCHECK(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) { |
| i::Heap* heap = reinterpret_cast<i::Isolate*>(GetIsolate())->heap(); |
| Utils::ApiCheck(*escape_slot_ == heap->the_hole_value(), |
| "EscapeableHandleScope::Escape", |
| "Escape value set twice"); |
| if (escape_value == NULL) { |
| *escape_slot_ = 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); |
| i::HandleScopeImplementer* impl = isolate->handle_scope_implementer(); |
| impl->EnterContext(env); |
| impl->SaveContext(isolate->context()); |
| isolate->set_context(*env); |
| } |
| |
| |
| void Context::Exit() { |
| i::Handle<i::Context> env = Utils::OpenHandle(this); |
| i::Isolate* isolate = env->GetIsolate(); |
| ENTER_V8(isolate); |
| i::HandleScopeImplementer* impl = isolate->handle_scope_implementer(); |
| if (!Utils::ApiCheck(impl->LastEnteredContextWas(env), |
| "v8::Context::Exit()", |
| "Cannot exit non-entered context")) { |
| return; |
| } |
| impl->LeaveContext(); |
| isolate->set_context(impl->RestoreContext()); |
| } |
| |
| |
| static void* DecodeSmiToAligned(i::Object* value, const char* location) { |
| Utils::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); |
| Utils::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 = |
| Utils::ApiCheck(env->IsNativeContext(), |
| location, |
| "Not a native context") && |
| Utils::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 (!Utils::ApiCheck(can_grow, location, "Index too large")) { |
| return i::Handle<i::FixedArray>(); |
| } |
| int new_size = i::Max(index, data->length() << 1) + 1; |
| data = i::FixedArray::CopySize(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); |
| DCHECK_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)); |
| DCHECK_EQ(value, GetAlignedPointerFromEmbedderData(index)); |
| } |
| |
| |
| // --- 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(v8::internal::Isolate* isolate, int size) { |
| 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(v8::internal::Isolate* isolate) : obj_(isolate, 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) { |
| DCHECK(0 <= offset); |
| DCHECK(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::Isolate* isolate, i::Handle<i::Object> value) { |
| int length = this->length(); |
| int size = obj_.size(); |
| if (length == size - 1) { |
| i::Factory* factory = isolate->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(isolate).value(); |
| Utils::OpenHandle(templ)->set_property_list(*list); |
| } |
| NeanderArray array(list); |
| array.add(isolate, isolate->factory()->NewNumberFromInt(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(isolate, value); |
| } |
| } |
| |
| |
| void Template::Set(v8::Handle<Name> name, |
| v8::Handle<Data> value, |
| v8::PropertyAttribute attribute) { |
| i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); |
| ENTER_V8(isolate); |
| i::HandleScope scope(isolate); |
| const int kSize = 3; |
| v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); |
| v8::Handle<v8::Data> data[kSize] = { |
| name, |
| value, |
| v8::Integer::New(v8_isolate, attribute)}; |
| TemplateSet(isolate, this, kSize, data); |
| } |
| |
| |
| void Template::SetAccessorProperty( |
| v8::Local<v8::Name> name, |
| v8::Local<FunctionTemplate> getter, |
| v8::Local<FunctionTemplate> setter, |
| v8::PropertyAttribute attribute, |
| v8::AccessControl access_control) { |
| // TODO(verwaest): Remove |access_control|. |
| DCHECK_EQ(v8::DEFAULT, access_control); |
| i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); |
| ENTER_V8(isolate); |
| DCHECK(!name.IsEmpty()); |
| DCHECK(!getter.IsEmpty() || !setter.IsEmpty()); |
| i::HandleScope scope(isolate); |
| const int kSize = 5; |
| v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); |
| v8::Handle<v8::Data> data[kSize] = { |
| name, |
| getter, |
| setter, |
| v8::Integer::New(v8_isolate, attribute)}; |
| 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* i_isolate = Utils::OpenHandle(this)->GetIsolate(); |
| ENTER_V8(i_isolate); |
| i::Handle<i::Object> result(Utils::OpenHandle(this)->prototype_template(), |
| i_isolate); |
| if (result->IsUndefined()) { |
| v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(i_isolate); |
| result = Utils::OpenHandle(*ObjectTemplate::New(isolate)); |
| 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); |
| LOG_API(i_isolate, "FunctionTemplate::New"); |
| ENTER_V8(i_isolate); |
| return FunctionTemplateNew( |
| i_isolate, callback, data, signature, length, false); |
| } |
| |
| |
| Local<Signature> Signature::New(Isolate* isolate, |
| Handle<FunctionTemplate> receiver, int argc, |
| Handle<FunctionTemplate> argv[]) { |
| i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); |
| 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<AccessorSignature> AccessorSignature::New( |
| Isolate* isolate, |
| 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(); |
| 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::Handle<i::TypeSwitchInfo> info = Utils::OpenHandle(this); |
| LOG_API(info->GetIsolate(), "TypeSwitch::match"); |
| i::Handle<i::Object> obj = Utils::OpenHandle(*value); |
| 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<Name> 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); |
| 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<Name> 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<Name> 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::Handle<i::FunctionTemplateInfo> handle = Utils::OpenHandle(this, true); |
| if (!Utils::ApiCheck(!handle.is_null(), |
| "v8::FunctionTemplate::InstanceTemplate()", |
| "Reading from empty handle")) { |
| return Local<ObjectTemplate>(); |
| } |
| i::Isolate* isolate = handle->GetIsolate(); |
| ENTER_V8(isolate); |
| 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) { |
| 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( |
| i::Isolate* isolate, |
| 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, isolate); |
| } |
| Local<FunctionTemplate> templ = |
| FunctionTemplate::New(reinterpret_cast<Isolate*>(isolate)); |
| 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::Isolate* isolate = info->GetIsolate(); |
| i::Handle<i::Object> list(info->property_accessors(), isolate); |
| if (list->IsUndefined()) { |
| list = NeanderArray(isolate).value(); |
| info->set_property_accessors(*list); |
| } |
| NeanderArray array(list); |
| array.add(isolate, obj); |
| } |
| |
| |
| static inline i::Handle<i::TemplateInfo> GetTemplateInfo( |
| i::Isolate* isolate, |
| Template* template_obj) { |
| return Utils::OpenHandle(template_obj); |
| } |
| |
| |
| // TODO(dcarney): remove this with ObjectTemplate::SetAccessor |
| static inline i::Handle<i::TemplateInfo> GetTemplateInfo( |
| i::Isolate* isolate, |
| ObjectTemplate* object_template) { |
| EnsureConstructor(isolate, object_template); |
| return Utils::OpenHandle(object_template); |
| } |
| |
| |
| template<typename Getter, typename Setter, typename Data, typename Template> |
| static bool TemplateSetAccessor( |
| Template* template_obj, |
| v8::Local<Name> 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(isolate, template_obj); |
| AddPropertyToTemplate(info, obj); |
| return true; |
| } |
| |
| |
| bool Template::SetDeclaredAccessor( |
| Local<Name> 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 Template::SetNativeDataProperty(v8::Local<Name> name, |
| AccessorNameGetterCallback getter, |
| AccessorNameSetterCallback 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::SetAccessor(v8::Handle<Name> name, |
| AccessorNameGetterCallback getter, |
| AccessorNameSetterCallback 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(isolate, 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(isolate, 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(isolate, 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(isolate, 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(isolate, 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 (!Utils::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(isolate, this); |
| } |
| Utils::OpenHandle(this)->set_internal_field_count(i::Smi::FromInt(value)); |
| } |
| |
| |
| // --- S c r i p t s --- |
| |
| |
| // Internally, UnboundScript is a SharedFunctionInfo, and Script is a |
| // JSFunction. |
| |
| ScriptCompiler::CachedData::CachedData(const uint8_t* data_, int length_, |
| BufferPolicy buffer_policy_) |
| : data(data_), length(length_), buffer_policy(buffer_policy_) {} |
| |
| |
| ScriptCompiler::CachedData::~CachedData() { |
| if (buffer_policy == BufferOwned) { |
| delete[] data; |
| } |
| } |
| |
| |
| ScriptCompiler::StreamedSource::StreamedSource(ExternalSourceStream* stream, |
| Encoding encoding) |
| : impl_(new i::StreamedSource(stream, encoding)) {} |
| |
| |
| ScriptCompiler::StreamedSource::~StreamedSource() { delete impl_; } |
| |
| |
| const ScriptCompiler::CachedData* |
| ScriptCompiler::StreamedSource::GetCachedData() const { |
| return impl_->cached_data.get(); |
| } |
| |
| |
| Local<Script> UnboundScript::BindToCurrentContext() { |
| i::Handle<i::HeapObject> obj = |
| i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this)); |
| i::Handle<i::SharedFunctionInfo> |
| function_info(i::SharedFunctionInfo::cast(*obj), obj->GetIsolate()); |
| i::Handle<i::JSFunction> function = |
| obj->GetIsolate()->factory()->NewFunctionFromSharedFunctionInfo( |
| function_info, obj->GetIsolate()->global_context()); |
| return ToApiHandle<Script>(function); |
| } |
| |
| |
| int UnboundScript::GetId() { |
| i::Handle<i::HeapObject> obj = |
| i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this)); |
| i::Isolate* isolate = obj->GetIsolate(); |
| ON_BAILOUT(isolate, "v8::UnboundScript::GetId()", return -1); |
| LOG_API(isolate, "v8::UnboundScript::GetId"); |
| { |
| i::HandleScope scope(isolate); |
| i::Handle<i::SharedFunctionInfo> function_info( |
| i::SharedFunctionInfo::cast(*obj)); |
| i::Handle<i::Script> script(i::Script::cast(function_info->script())); |
| return script->id()->value(); |
| } |
| } |
| |
| |
| int UnboundScript::GetLineNumber(int code_pos) { |
| i::Handle<i::SharedFunctionInfo> obj = |
| i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this)); |
| i::Isolate* isolate = obj->GetIsolate(); |
| ON_BAILOUT(isolate, "v8::UnboundScript::GetLineNumber()", return -1); |
| LOG_API(isolate, "UnboundScript::GetLineNumber"); |
| if (obj->script()->IsScript()) { |
| i::Handle<i::Script> script(i::Script::cast(obj->script())); |
| return i::Script::GetLineNumber(script, code_pos); |
| } else { |
| return -1; |
| } |
| } |
| |
| |
| Handle<Value> UnboundScript::GetScriptName() { |
| i::Handle<i::SharedFunctionInfo> obj = |
| i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this)); |
| i::Isolate* isolate = obj->GetIsolate(); |
| ON_BAILOUT(isolate, "v8::UnboundScript::GetName()", |
| return Handle<String>()); |
| LOG_API(isolate, "UnboundScript::GetName"); |
| if (obj->script()->IsScript()) { |
| i::Object* name = i::Script::cast(obj->script())->name(); |
| return Utils::ToLocal(i::Handle<i::Object>(name, isolate)); |
| } else { |
| return Handle<String>(); |
| } |
| } |
| |
| |
| Handle<Value> UnboundScript::GetSourceURL() { |
| i::Handle<i::SharedFunctionInfo> obj = |
| i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this)); |
| i::Isolate* isolate = obj->GetIsolate(); |
| ON_BAILOUT(isolate, "v8::UnboundScript::GetSourceURL()", |
| return Handle<String>()); |
| LOG_API(isolate, "UnboundScript::GetSourceURL"); |
| if (obj->script()->IsScript()) { |
| i::Object* url = i::Script::cast(obj->script())->source_url(); |
| return Utils::ToLocal(i::Handle<i::Object>(url, isolate)); |
| } else { |
| return Handle<String>(); |
| } |
| } |
| |
| |
| Handle<Value> UnboundScript::GetSourceMappingURL() { |
| i::Handle<i::SharedFunctionInfo> obj = |
| i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this)); |
| i::Isolate* isolate = obj->GetIsolate(); |
| ON_BAILOUT(isolate, "v8::UnboundScript::GetSourceMappingURL()", |
| return Handle<String>()); |
| LOG_API(isolate, "UnboundScript::GetSourceMappingURL"); |
| if (obj->script()->IsScript()) { |
| i::Object* url = i::Script::cast(obj->script())->source_mapping_url(); |
| return Utils::ToLocal(i::Handle<i::Object>(url, isolate)); |
| } else { |
| return Handle<String>(); |
| } |
| } |
| |
| |
| Local<Value> Script::Run() { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this, true); |
| // If execution is terminating, Compile(..)->Run() requires this |
| // check. |
| if (obj.is_null()) return Local<Value>(); |
| i::Isolate* isolate = i::Handle<i::HeapObject>::cast(obj)->GetIsolate(); |
| ON_BAILOUT(isolate, "v8::Script::Run()", return Local<Value>()); |
| LOG_API(isolate, "Script::Run"); |
| ENTER_V8(isolate); |
| i::TimerEventScope<i::TimerEventExecute> timer_scope(isolate); |
| i::HandleScope scope(isolate); |
| i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(obj); |
| EXCEPTION_PREAMBLE(isolate); |
| i::Handle<i::Object> receiver(isolate->global_proxy(), isolate); |
| i::Handle<i::Object> result; |
| has_pending_exception = !i::Execution::Call( |
| isolate, fun, receiver, 0, NULL).ToHandle(&result); |
| EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Value>()); |
| return Utils::ToLocal(scope.CloseAndEscape(result)); |
| } |
| |
| |
| Local<UnboundScript> Script::GetUnboundScript() { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| return ToApiHandle<UnboundScript>( |
| i::Handle<i::SharedFunctionInfo>(i::JSFunction::cast(*obj)->shared())); |
| } |
| |
| |
| Local<UnboundScript> ScriptCompiler::CompileUnbound( |
| Isolate* v8_isolate, |
| Source* source, |
| CompileOptions options) { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| ON_BAILOUT(isolate, "v8::ScriptCompiler::CompileUnbound()", |
| return Local<UnboundScript>()); |
| |
| // Support the old API for a transition period: |
| // - kProduceToCache -> kProduceParserCache |
| // - kNoCompileOptions + cached_data != NULL -> kConsumeParserCache |
| if (options == kProduceDataToCache) { |
| options = kProduceParserCache; |
| } else if (options == kNoCompileOptions && source->cached_data) { |
| options = kConsumeParserCache; |
| } |
| |
| i::ScriptData* script_data = NULL; |
| if (options == kConsumeParserCache || options == kConsumeCodeCache) { |
| DCHECK(source->cached_data); |
| // ScriptData takes care of pointer-aligning the data. |
| script_data = new i::ScriptData(source->cached_data->data, |
| source->cached_data->length); |
| } |
| |
| i::Handle<i::String> str = Utils::OpenHandle(*(source->source_string)); |
| LOG_API(isolate, "ScriptCompiler::CompileUnbound"); |
| 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 (!source->resource_name.IsEmpty()) { |
| name_obj = Utils::OpenHandle(*(source->resource_name)); |
| } |
| if (!source->resource_line_offset.IsEmpty()) { |
| line_offset = static_cast<int>(source->resource_line_offset->Value()); |
| } |
| if (!source->resource_column_offset.IsEmpty()) { |
| column_offset = |
| static_cast<int>(source->resource_column_offset->Value()); |
| } |
| if (!source->resource_is_shared_cross_origin.IsEmpty()) { |
| v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); |
| is_shared_cross_origin = |
| source->resource_is_shared_cross_origin == v8::True(v8_isolate); |
| } |
| EXCEPTION_PREAMBLE(isolate); |
| i::Handle<i::SharedFunctionInfo> result = i::Compiler::CompileScript( |
| str, name_obj, line_offset, column_offset, is_shared_cross_origin, |
| isolate->global_context(), NULL, &script_data, options, |
| i::NOT_NATIVES_CODE); |
| has_pending_exception = result.is_null(); |
| if (has_pending_exception && script_data != NULL) { |
| // This case won't happen during normal operation; we have compiled |
| // successfully and produced cached data, and but the second compilation |
| // of the same source code fails. |
| delete script_data; |
| script_data = NULL; |
| } |
| EXCEPTION_BAILOUT_CHECK(isolate, Local<UnboundScript>()); |
| raw_result = *result; |
| |
| if ((options == kProduceParserCache || options == kProduceCodeCache) && |
| script_data != NULL) { |
| // script_data now contains the data that was generated. source will |
| // take the ownership. |
| source->cached_data = new CachedData( |
| script_data->data(), script_data->length(), CachedData::BufferOwned); |
| script_data->ReleaseDataOwnership(); |
| } |
| delete script_data; |
| } |
| i::Handle<i::SharedFunctionInfo> result(raw_result, isolate); |
| return ToApiHandle<UnboundScript>(result); |
| } |
| |
| |
| Local<Script> ScriptCompiler::Compile( |
| Isolate* v8_isolate, |
| Source* source, |
| CompileOptions options) { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| ON_BAILOUT(isolate, "v8::ScriptCompiler::Compile()", return Local<Script>()); |
| LOG_API(isolate, "ScriptCompiler::CompiletBound()"); |
| ENTER_V8(isolate); |
| Local<UnboundScript> generic = CompileUnbound(v8_isolate, source, options); |
| if (generic.IsEmpty()) return Local<Script>(); |
| return generic->BindToCurrentContext(); |
| } |
| |
| |
| ScriptCompiler::ScriptStreamingTask* ScriptCompiler::StartStreamingScript( |
| Isolate* v8_isolate, StreamedSource* source, CompileOptions options) { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| if (!isolate->global_context().is_null() && |
| !isolate->global_context()->IsNativeContext()) { |
| // The context chain is non-trivial, and constructing the corresponding |
| // non-trivial Scope chain outside the V8 heap is not implemented. Don't |
| // stream the script. This will only occur if Harmony scoping is enabled and |
| // a previous script has introduced "let" or "const" variables. TODO(marja): |
| // Implement externalizing ScopeInfos and constructing non-trivial Scope |
| // chains independent of the V8 heap so that we can stream also in this |
| // case. |
| return NULL; |
| } |
| return new i::BackgroundParsingTask(source->impl(), options, |
| i::FLAG_stack_size, isolate); |
| } |
| |
| |
| Local<Script> ScriptCompiler::Compile(Isolate* v8_isolate, |
| StreamedSource* v8_source, |
| Handle<String> full_source_string, |
| const ScriptOrigin& origin) { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| i::StreamedSource* source = v8_source->impl(); |
| ON_BAILOUT(isolate, "v8::ScriptCompiler::Compile()", return Local<Script>()); |
| LOG_API(isolate, "ScriptCompiler::Compile()"); |
| ENTER_V8(isolate); |
| i::SharedFunctionInfo* raw_result = NULL; |
| |
| { |
| i::HandleScope scope(isolate); |
| i::Handle<i::String> str = Utils::OpenHandle(*(full_source_string)); |
| i::Handle<i::Script> script = isolate->factory()->NewScript(str); |
| if (!origin.ResourceName().IsEmpty()) { |
| script->set_name(*Utils::OpenHandle(*(origin.ResourceName()))); |
| } |
| if (!origin.ResourceLineOffset().IsEmpty()) { |
| script->set_line_offset(i::Smi::FromInt( |
| static_cast<int>(origin.ResourceLineOffset()->Value()))); |
| } |
| if (!origin.ResourceColumnOffset().IsEmpty()) { |
| script->set_column_offset(i::Smi::FromInt( |
| static_cast<int>(origin.ResourceColumnOffset()->Value()))); |
| } |
| if (!origin.ResourceIsSharedCrossOrigin().IsEmpty()) { |
| script->set_is_shared_cross_origin(origin.ResourceIsSharedCrossOrigin() == |
| v8::True(v8_isolate)); |
| } |
| source->info->set_script(script); |
| source->info->SetContext(isolate->global_context()); |
| |
| EXCEPTION_PREAMBLE(isolate); |
| |
| // Do the parsing tasks which need to be done on the main thread. This will |
| // also handle parse errors. |
| source->parser->Internalize(); |
| |
| i::Handle<i::SharedFunctionInfo> result = |
| i::Handle<i::SharedFunctionInfo>::null(); |
| if (source->info->function() != NULL) { |
| // Parsing has succeeded. |
| result = |
| i::Compiler::CompileStreamedScript(source->info.get(), str->length()); |
| } |
| has_pending_exception = result.is_null(); |
| if (has_pending_exception) isolate->ReportPendingMessages(); |
| EXCEPTION_BAILOUT_CHECK(isolate, Local<Script>()); |
| |
| raw_result = *result; |
| // The Handle<Script> will go out of scope soon; make sure CompilationInfo |
| // doesn't point to it. |
| source->info->set_script(i::Handle<i::Script>()); |
| } // HandleScope goes out of scope. |
| i::Handle<i::SharedFunctionInfo> result(raw_result, isolate); |
| Local<UnboundScript> generic = ToApiHandle<UnboundScript>(result); |
| if (generic.IsEmpty()) { |
| return Local<Script>(); |
| } |
| return generic->BindToCurrentContext(); |
| } |
| |
| |
| Local<Script> Script::Compile(v8::Handle<String> source, |
| v8::ScriptOrigin* origin) { |
| i::Handle<i::String> str = Utils::OpenHandle(*source); |
| if (origin) { |
| ScriptCompiler::Source script_source(source, *origin); |
| return ScriptCompiler::Compile( |
| reinterpret_cast<v8::Isolate*>(str->GetIsolate()), |
| &script_source); |
| } |
| ScriptCompiler::Source script_source(source); |
| return ScriptCompiler::Compile( |
| reinterpret_cast<v8::Isolate*>(str->GetIsolate()), |
| &script_source); |
| } |
| |
| |
| Local<Script> Script::Compile(v8::Handle<String> source, |
| v8::Handle<String> file_name) { |
| ScriptOrigin origin(file_name); |
| return Compile(source, &origin); |
| } |
| |
| |
| // --- E x c e p t i o n s --- |
| |
| |
| v8::TryCatch::TryCatch() |
| : isolate_(i::Isolate::Current()), |
| next_(isolate_->try_catch_handler()), |
| is_verbose_(false), |
| can_continue_(true), |
| capture_message_(true), |
| rethrow_(false), |
| has_terminated_(false) { |
| ResetInternal(); |
| // Special handling for simulators which have a separate JS stack. |
| js_stack_comparable_address_ = |
| reinterpret_cast<void*>(v8::internal::SimulatorStack::RegisterCTryCatch( |
| v8::internal::GetCurrentStackPosition())); |
| isolate_->RegisterTryCatchHandler(this); |
| } |
| |
| |
| v8::TryCatch::TryCatch(v8::Isolate* isolate) |
| : isolate_(reinterpret_cast<i::Isolate*>(isolate)), |
| next_(isolate_->try_catch_handler()), |
| is_verbose_(false), |
| can_continue_(true), |
| capture_message_(true), |
| rethrow_(false), |
| has_terminated_(false) { |
| ResetInternal(); |
| // Special handling for simulators which have a separate JS stack. |
| js_stack_comparable_address_ = |
| reinterpret_cast<void*>(v8::internal::SimulatorStack::RegisterCTryCatch( |
| v8::internal::GetCurrentStackPosition())); |
| isolate_->RegisterTryCatchHandler(this); |
| } |
| |
| |
| v8::TryCatch::~TryCatch() { |
| 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); |
| v8::internal::SimulatorStack::UnregisterCTryCatch(); |
| reinterpret_cast<Isolate*>(isolate_)->ThrowException(exc); |
| DCHECK(!isolate_->thread_local_top()->rethrowing_message_); |
| } else { |
| if (HasCaught() && isolate_->has_scheduled_exception()) { |
| // If an exception was caught but is still scheduled because no API call |
| // promoted it, then it is canceled to prevent it from being propagated. |
| // Note that this will not cancel termination exceptions. |
| isolate_->CancelScheduledExceptionFromTryCatch(this); |
| } |
| isolate_->UnregisterTryCatchHandler(this); |
| v8::internal::SimulatorStack::UnregisterCTryCatch(); |
| } |
| } |
| |
| |
| 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 { |
| 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 { |
| 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(); |
| EXCEPTION_PREAMBLE(isolate_); |
| Maybe<bool> maybe = i::JSReceiver::HasProperty(obj, name); |
| has_pending_exception = !maybe.has_value; |
| EXCEPTION_BAILOUT_CHECK(isolate_, v8::Local<Value>()); |
| if (!maybe.value) return v8::Local<Value>(); |
| i::Handle<i::Object> value; |
| if (!i::Object::GetProperty(obj, name).ToHandle(&value)) { |
| return v8::Local<Value>(); |
| } |
| return v8::Utils::ToLocal(scope.CloseAndEscape(value)); |
| } else { |
| return v8::Local<Value>(); |
| } |
| } |
| |
| |
| v8::Local<v8::Message> v8::TryCatch::Message() const { |
| i::Object* message = reinterpret_cast<i::Object*>(message_obj_); |
| DCHECK(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() { |
| if (!rethrow_ && HasCaught() && isolate_->has_scheduled_exception()) { |
| // If an exception was caught but is still scheduled because no API call |
| // promoted it, then it is canceled to prevent it from being propagated. |
| // Note that this will not cancel termination exceptions. |
| isolate_->CancelScheduledExceptionFromTryCatch(this); |
| } |
| ResetInternal(); |
| } |
| |
| |
| void v8::TryCatch::ResetInternal() { |
| 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); |
| } |
| |
| |
| ScriptOrigin Message::GetScriptOrigin() const { |
| i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); |
| i::Handle<i::JSMessageObject> message = |
| i::Handle<i::JSMessageObject>::cast(Utils::OpenHandle(this)); |
| i::Handle<i::Object> script_wraper = |
| i::Handle<i::Object>(message->script(), isolate); |
| i::Handle<i::JSValue> script_value = |
| i::Handle<i::JSValue>::cast(script_wraper); |
| i::Handle<i::Script> script(i::Script::cast(script_value->value())); |
| i::Handle<i::Object> scriptName(i::Script::GetNameOrSourceURL(script)); |
| v8::Isolate* v8_isolate = |
| reinterpret_cast<v8::Isolate*>(script->GetIsolate()); |
| v8::ScriptOrigin origin( |
| Utils::ToLocal(scriptName), |
| v8::Integer::New(v8_isolate, script->line_offset()->value()), |
| v8::Integer::New(v8_isolate, script->column_offset()->value()), |
| Handle<Boolean>(), |
| v8::Integer::New(v8_isolate, script->id()->value())); |
| return origin; |
| } |
| |
| |
| v8::Handle<Value> Message::GetScriptResourceName() const { |
| return GetScriptOrigin().ResourceName(); |
| } |
| |
| |
| 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)); |
| } |
| |
| |
| MUST_USE_RESULT static i::MaybeHandle<i::Object> CallV8HeapFunction( |
| i::Isolate* isolate, const char* name, i::Handle<i::Object> recv, int argc, |
| i::Handle<i::Object> argv[]) { |
| i::Handle<i::Object> object_fun = |
| i::Object::GetProperty( |
| isolate, isolate->js_builtins_object(), name).ToHandleChecked(); |
| i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>::cast(object_fun); |
| return i::Execution::Call(isolate, fun, recv, argc, argv); |
| } |
| |
| |
| MUST_USE_RESULT static i::MaybeHandle<i::Object> CallV8HeapFunction( |
| i::Isolate* isolate, const char* name, i::Handle<i::Object> data) { |
| i::Handle<i::Object> argv[] = { data }; |
| return CallV8HeapFunction(isolate, name, isolate->js_builtins_object(), |
| arraysize(argv), argv); |
| } |
| |
| |
| 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; |
| has_pending_exception = |
| !CallV8HeapFunction(isolate, "GetLineNumber", Utils::OpenHandle(this)) |
| .ToHandle(&result); |
| 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(); |
| ON_BAILOUT(isolate, "v8::Message::GetStartColumn()", return kNoColumnInfo); |
| 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; |
| has_pending_exception = |
| !CallV8HeapFunction(isolate, "GetPositionInLine", data_obj) |
| .ToHandle(&start_col_obj); |
| EXCEPTION_BAILOUT_CHECK(isolate, 0); |
| return static_cast<int>(start_col_obj->Number()); |
| } |
| |
| |
| int Message::GetEndColumn() const { |
| i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); |
| ON_BAILOUT(isolate, "v8::Message::GetEndColumn()", return kNoColumnInfo); |
| 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; |
| has_pending_exception = |
| !CallV8HeapFunction(isolate, "GetPositionInLine", data_obj) |
| .ToHandle(&start_col_obj); |
| 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; |
| has_pending_exception = |
| !CallV8HeapFunction(isolate, "GetSourceLine", Utils::OpenHandle(this)) |
| .ToHandle(&result); |
| 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); |
| } |
| |
| |
| // --- 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::Handle<i::Object> obj = |
| i::Object::GetElement(isolate, self, index).ToHandleChecked(); |
| i::Handle<i::JSObject> jsobj = i::Handle<i::JSObject>::cast(obj); |
| return scope.Escape(Utils::StackFrameToLocal(jsobj)); |
| } |
| |
| |
| 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); |
| // TODO(dcarney): remove when ScriptDebugServer is fixed. |
| options = static_cast<StackTraceOptions>( |
| static_cast<int>(options) | kExposeFramesAcrossSecurityOrigins); |
| i::Handle<i::JSArray> stackTrace = |
| i_isolate->CaptureCurrentStackTrace(frame_limit, options); |
| return Utils::StackTraceToLocal(stackTrace); |
| } |
| |
| |
| // --- S t a c k F r a m e --- |
| |
| static int getIntProperty(const StackFrame* f, const char* propertyName, |
| int defaultValue) { |
| i::Isolate* isolate = Utils::OpenHandle(f)->GetIsolate(); |
| ENTER_V8(isolate); |
| i::HandleScope scope(isolate); |
| i::Handle<i::JSObject> self = Utils::OpenHandle(f); |
| i::Handle<i::Object> obj = |
| i::Object::GetProperty(isolate, self, propertyName).ToHandleChecked(); |
| return obj->IsSmi() ? i::Smi::cast(*obj)->value() : defaultValue; |
| } |
| |
| |
| int StackFrame::GetLineNumber() const { |
| return getIntProperty(this, "lineNumber", Message::kNoLineNumberInfo); |
| } |
| |
| |
| int StackFrame::GetColumn() const { |
| return getIntProperty(this, "column", Message::kNoColumnInfo); |
| } |
| |
| |
| int StackFrame::GetScriptId() const { |
| return getIntProperty(this, "scriptId", Message::kNoScriptIdInfo); |
| } |
| |
| |
| static Local<String> getStringProperty(const StackFrame* f, |
| const char* propertyName) { |
| i::Isolate* isolate = Utils::OpenHandle(f)->GetIsolate(); |
| ENTER_V8(isolate); |
| EscapableHandleScope scope(reinterpret_cast<Isolate*>(isolate)); |
| i::Handle<i::JSObject> self = Utils::OpenHandle(f); |
| i::Handle<i::Object> obj = |
| i::Object::GetProperty(isolate, self, propertyName).ToHandleChecked(); |
| return obj->IsString() |
| ? scope.Escape(Local<String>::Cast(Utils::ToLocal(obj))) |
| : Local<String>(); |
| } |
| |
| |
| Local<String> StackFrame::GetScriptName() const { |
| return getStringProperty(this, "scriptName"); |
| } |
| |
| |
| Local<String> StackFrame::GetScriptNameOrSourceURL() const { |
| return getStringProperty(this, "scriptNameOrSourceURL"); |
| } |
| |
| |
| Local<String> StackFrame::GetFunctionName() const { |
| return getStringProperty(this, "functionName"); |
| } |
| |
| |
| static bool getBoolProperty(const StackFrame* f, const char* propertyName) { |
| i::Isolate* isolate = Utils::OpenHandle(f)->GetIsolate(); |
| ENTER_V8(isolate); |
| i::HandleScope scope(isolate); |
| i::Handle<i::JSObject> self = Utils::OpenHandle(f); |
| i::Handle<i::Object> obj = |
| i::Object::GetProperty(isolate, self, propertyName).ToHandleChecked(); |
| return obj->IsTrue(); |
| } |
| |
| bool StackFrame::IsEval() const { return getBoolProperty(this, "isEval"); } |
| |
| |
| bool StackFrame::IsConstructor() const { |
| return getBoolProperty(this, "isConstructor"); |
| } |
| |
| |
| // --- J S O N --- |
| |
| Local<Value> JSON::Parse(Local<String> json_string) { |
| i::Handle<i::String> string = Utils::OpenHandle(*json_string); |
| i::Isolate* isolate = string->GetIsolate(); |
| ENTER_V8(isolate); |
| i::HandleScope scope(isolate); |
| i::Handle<i::String> source = i::String::Flatten(string); |
| EXCEPTION_PREAMBLE(isolate); |
| i::MaybeHandle<i::Object> maybe_result = |
| source->IsSeqOneByteString() ? i::JsonParser<true>::Parse(source) |
| : i::JsonParser<false>::Parse(source); |
| i::Handle<i::Object> result; |
| has_pending_exception = !maybe_result.ToHandle(&result); |
| EXCEPTION_BAILOUT_CHECK(isolate, Local<Object>()); |
| return Utils::ToLocal( |
| i::Handle<i::Object>::cast(scope.CloseAndEscape(result))); |
| } |
| |
| |
| // --- D a t a --- |
| |
| bool Value::FullIsUndefined() const { |
| bool result = Utils::OpenHandle(this)->IsUndefined(); |
| DCHECK_EQ(result, QuickIsUndefined()); |
| return result; |
| } |
| |
| |
| bool Value::FullIsNull() const { |
| bool result = Utils::OpenHandle(this)->IsNull(); |
| DCHECK_EQ(result, QuickIsNull()); |
| return result; |
| } |
| |
| |
| bool Value::IsTrue() const { |
| return Utils::OpenHandle(this)->IsTrue(); |
| } |
| |
| |
| bool Value::IsFalse() const { |
| return Utils::OpenHandle(this)->IsFalse(); |
| } |
| |
| |
| bool Value::IsFunction() const { |
| return Utils::OpenHandle(this)->IsJSFunction(); |
| } |
| |
| |
| bool Value::IsName() const { |
| return Utils::OpenHandle(this)->IsName(); |
| } |
| |
| |
| bool Value::FullIsString() const { |
| bool result = Utils::OpenHandle(this)->IsString(); |
| DCHECK_EQ(result, QuickIsString()); |
| return result; |
| } |
| |
| |
| bool Value::IsSymbol() const { |
| return Utils::OpenHandle(this)->IsSymbol(); |
| } |
| |
| |
| bool Value::IsArray() const { |
| return Utils::OpenHandle(this)->IsJSArray(); |
| } |
| |
| |
| bool Value::IsArrayBuffer() const { |
| return Utils::OpenHandle(this)->IsJSArrayBuffer(); |
| } |
| |
| |
| bool Value::IsArrayBufferView() const { |
| return Utils::OpenHandle(this)->IsJSArrayBufferView(); |
| } |
| |
| |
| bool Value::IsTypedArray() const { |
| return Utils::OpenHandle(this)->IsJSTypedArray(); |
| } |
| |
| |
| #define VALUE_IS_TYPED_ARRAY(Type, typeName, TYPE, ctype, size) \ |
| bool Value::Is##Type##Array() const { \ |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); \ |
| return obj->IsJSTypedArray() && \ |
| i::JSTypedArray::cast(*obj)->type() == kExternal##Type##Array; \ |
| } |
| |
| TYPED_ARRAYS(VALUE_IS_TYPED_ARRAY) |
| |
| #undef VALUE_IS_TYPED_ARRAY |
| |
| |
| bool Value::IsDataView() const { |
| return Utils::OpenHandle(this)->IsJSDataView(); |
| } |
| |
| |
| bool Value::IsObject() const { |
| return Utils::OpenHandle(this)->IsJSObject(); |
| } |
| |
| |
| bool Value::IsNumber() const { |
| return Utils::OpenHandle(this)->IsNumber(); |
| } |
| |
| |
| #define VALUE_IS_SPECIFIC_TYPE(Type, Class) \ |
| bool Value::Is##Type() const { \ |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); \ |
| if (!obj->IsHeapObject()) return false; \ |
| i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); \ |
| return obj->HasSpecificClassOf(isolate->heap()->Class##_string()); \ |
| } |
| |
| VALUE_IS_SPECIFIC_TYPE(ArgumentsObject, Arguments) |
| VALUE_IS_SPECIFIC_TYPE(BooleanObject, Boolean) |
| VALUE_IS_SPECIFIC_TYPE(NumberObject, Number) |
| VALUE_IS_SPECIFIC_TYPE(StringObject, String) |
| VALUE_IS_SPECIFIC_TYPE(SymbolObject, Symbol) |
| VALUE_IS_SPECIFIC_TYPE(Date, Date) |
| VALUE_IS_SPECIFIC_TYPE(Map, Map) |
| VALUE_IS_SPECIFIC_TYPE(Set, Set) |
| VALUE_IS_SPECIFIC_TYPE(WeakMap, WeakMap) |
| VALUE_IS_SPECIFIC_TYPE(WeakSet, WeakSet) |
| |
| #undef VALUE_IS_SPECIFIC_TYPE |
| |
| |
| bool Value::IsBoolean() const { |
| return Utils::OpenHandle(this)->IsBoolean(); |
| } |
| |
| |
| bool Value::IsExternal() const { |
| return Utils::OpenHandle(this)->IsExternal(); |
| } |
| |
| |
| bool Value::IsInt32() const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| if (obj->IsSmi()) return true; |
| if (obj->IsNumber()) { |
| return i::IsInt32Double(obj->Number()); |
| } |
| return false; |
| } |
| |
| |
| bool Value::IsUint32() const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| if (obj->IsSmi()) return i::Smi::cast(*obj)->value() >= 0; |
| if (obj->IsNumber()) { |
| double value = obj->Number(); |
| return !i::IsMinusZero(value) && |
| value >= 0 && |
| value <= i::kMaxUInt32 && |
| value == i::FastUI2D(i::FastD2UI(value)); |
| } |
| return false; |
| } |
| |
| |
| static bool CheckConstructor(i::Isolate* isolate, |
| i::Handle<i::JSObject> obj, |
| const char* class_name) { |
| i::Handle<i::Object> constr(obj->map()->constructor(), isolate); |
| if (!constr->IsJSFunction()) return false; |
| i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(constr); |
| return func->shared()->native() && constr.is_identical_to( |
| i::Object::GetProperty(isolate, |
| isolate->js_builtins_object(), |
| class_name).ToHandleChecked()); |
| } |
| |
| |
| bool Value::IsNativeError() const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| if (obj->IsJSObject()) { |
| i::Handle<i::JSObject> js_obj(i::JSObject::cast(*obj)); |
| i::Isolate* isolate = js_obj->GetIsolate(); |
| return CheckConstructor(isolate, js_obj, "$Error") || |
| CheckConstructor(isolate, js_obj, "$EvalError") || |
| CheckConstructor(isolate, js_obj, "$RangeError") || |
| CheckConstructor(isolate, js_obj, "$ReferenceError") || |
| CheckConstructor(isolate, js_obj, "$SyntaxError") || |
| CheckConstructor(isolate, js_obj, "$TypeError") || |
| CheckConstructor(isolate, js_obj, "$URIError"); |
| } else { |
| return false; |
| } |
| } |
| |
| |
| bool Value::IsRegExp() const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| return obj->IsJSRegExp(); |
| } |
| |
| |
| bool Value::IsGeneratorFunction() const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| if (!obj->IsJSFunction()) return false; |
| i::Handle<i::JSFunction> func = i::Handle<i::JSFunction>::cast(obj); |
| return func->shared()->is_generator(); |
| } |
| |
| |
| bool Value::IsGeneratorObject() const { |
| return Utils::OpenHandle(this)->IsJSGeneratorObject(); |
| } |
| |
| |
| bool Value::IsMapIterator() const { |
| return Utils::OpenHandle(this)->IsJSMapIterator(); |
| } |
| |
| |
| bool Value::IsSetIterator() const { |
| return Utils::OpenHandle(this)->IsJSSetIterator(); |
| } |
| |
| |
| Local<String> Value::ToString(Isolate* v8_isolate) const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| i::Handle<i::Object> str; |
| if (obj->IsString()) { |
| str = obj; |
| } else { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| LOG_API(isolate, "ToString"); |
| ENTER_V8(isolate); |
| EXCEPTION_PREAMBLE(isolate); |
| has_pending_exception = !i::Execution::ToString( |
| isolate, obj).ToHandle(&str); |
| EXCEPTION_BAILOUT_CHECK(isolate, Local<String>()); |
| } |
| return ToApiHandle<String>(str); |
| } |
| |
| |
| Local<String> Value::ToDetailString(Isolate* v8_isolate) const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| i::Handle<i::Object> str; |
| if (obj->IsString()) { |
| str = obj; |
| } else { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| LOG_API(isolate, "ToDetailString"); |
| ENTER_V8(isolate); |
| EXCEPTION_PREAMBLE(isolate); |
| has_pending_exception = !i::Execution::ToDetailString( |
| isolate, obj).ToHandle(&str); |
| EXCEPTION_BAILOUT_CHECK(isolate, Local<String>()); |
| } |
| return ToApiHandle<String>(str); |
| } |
| |
| |
| Local<v8::Object> Value::ToObject(Isolate* v8_isolate) const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| i::Handle<i::Object> val; |
| if (obj->IsJSObject()) { |
| val = obj; |
| } else { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| LOG_API(isolate, "ToObject"); |
| ENTER_V8(isolate); |
| EXCEPTION_PREAMBLE(isolate); |
| has_pending_exception = !i::Execution::ToObject( |
| isolate, obj).ToHandle(&val); |
| EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>()); |
| } |
| return ToApiHandle<Object>(val); |
| } |
| |
| |
| Local<Boolean> Value::ToBoolean(Isolate* v8_isolate) const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| if (obj->IsBoolean()) { |
| return ToApiHandle<Boolean>(obj); |
| } else { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| LOG_API(isolate, "ToBoolean"); |
| ENTER_V8(isolate); |
| i::Handle<i::Object> val = |
| isolate->factory()->ToBoolean(obj->BooleanValue()); |
| return ToApiHandle<Boolean>(val); |
| } |
| } |
| |
| |
| Local<Number> Value::ToNumber(Isolate* v8_isolate) const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| i::Handle<i::Object> num; |
| if (obj->IsNumber()) { |
| num = obj; |
| } else { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| LOG_API(isolate, "ToNumber"); |
| ENTER_V8(isolate); |
| EXCEPTION_PREAMBLE(isolate); |
| has_pending_exception = !i::Execution::ToNumber( |
| isolate, obj).ToHandle(&num); |
| EXCEPTION_BAILOUT_CHECK(isolate, Local<Number>()); |
| } |
| return ToApiHandle<Number>(num); |
| } |
| |
| |
| Local<Integer> Value::ToInteger(Isolate* v8_isolate) const { |
| i::Handle<i::Object> obj = Utils::OpenHandle(this); |
| i::Handle<i::Object> num; |
| if (obj->IsSmi()) { |
| num = obj; |
| } else { |
| i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate); |
| LOG_API(isolate, "ToInteger"); |
| ENTER_V8(isolate); |
| EXCEPTION_PREAMBLE(isolate); |
| has_pending_exception = !i::Execution::ToInteger( |
| isolate, obj).ToHandle(&num); |
| EXCEPTION_BAILOUT_CHECK(isolate, Local<Integer>()); |
| } |
|