// 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 // For memcpy, strlen. #ifdef V8_USE_ADDRESS_SANITIZER #include #endif // V8_USE_ADDRESS_SANITIZER #include // For isnan. #include "include/v8-debug.h" #include "include/v8-profiler.h" #include "include/v8-testing.h" #include "src/api-natives.h" #include "src/assert-scope.h" #include "src/background-parsing-task.h" #include "src/base/functional.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/char-predicates-inl.h" #include "src/code-stubs.h" #include "src/compiler.h" #include "src/context-measure.h" #include "src/contexts.h" #include "src/conversions-inl.h" #include "src/counters.h" #include "src/cpu-profiler.h" #include "src/debug/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/parser.h" #include "src/pending-compilation-error-handler.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/natives.h" #include "src/snapshot/snapshot.h" #include "src/startup-data-util.h" #include "src/unicode-inl.h" #include "src/v8.h" #include "src/v8threads.h" #include "src/version.h" #include "src/vm-state-inl.h" namespace v8 { #define LOG_API(isolate, expr) LOG(isolate, ApiEntryCall(expr)) #define ENTER_V8(isolate) i::VMState __state__((isolate)) #define PREPARE_FOR_EXECUTION_GENERIC(isolate, context, function_name, \ bailout_value, HandleScopeClass, \ do_callback) \ if (IsExecutionTerminatingCheck(isolate)) { \ return bailout_value; \ } \ HandleScopeClass handle_scope(isolate); \ CallDepthScope call_depth_scope(isolate, context, do_callback); \ LOG_API(isolate, function_name); \ ENTER_V8(isolate); \ bool has_pending_exception = false #define PREPARE_FOR_EXECUTION_WITH_CONTEXT( \ context, function_name, bailout_value, HandleScopeClass, do_callback) \ auto isolate = context.IsEmpty() \ ? i::Isolate::Current() \ : reinterpret_cast(context->GetIsolate()); \ PREPARE_FOR_EXECUTION_GENERIC(isolate, context, function_name, \ bailout_value, HandleScopeClass, do_callback); #define PREPARE_FOR_EXECUTION_WITH_ISOLATE(isolate, function_name, T) \ PREPARE_FOR_EXECUTION_GENERIC(isolate, Local(), function_name, \ MaybeLocal(), InternalEscapableScope, \ false); #define PREPARE_FOR_EXECUTION(context, function_name, T) \ PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, function_name, MaybeLocal(), \ InternalEscapableScope, false) #define PREPARE_FOR_EXECUTION_WITH_CALLBACK(context, function_name, T) \ PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, function_name, MaybeLocal(), \ InternalEscapableScope, true) #define PREPARE_FOR_EXECUTION_PRIMITIVE(context, function_name, T) \ PREPARE_FOR_EXECUTION_WITH_CONTEXT(context, function_name, Nothing(), \ i::HandleScope, false) #define EXCEPTION_BAILOUT_CHECK_SCOPED(isolate, value) \ do { \ if (has_pending_exception) { \ call_depth_scope.Escape(); \ return value; \ } \ } while (false) #define RETURN_ON_FAILED_EXECUTION(T) \ EXCEPTION_BAILOUT_CHECK_SCOPED(isolate, MaybeLocal()) #define RETURN_ON_FAILED_EXECUTION_PRIMITIVE(T) \ EXCEPTION_BAILOUT_CHECK_SCOPED(isolate, Nothing()) #define RETURN_TO_LOCAL_UNCHECKED(maybe_local, T) \ return maybe_local.FromMaybe(Local()); #define RETURN_ESCAPED(value) return handle_scope.Escape(value); namespace { Local ContextFromHeapObject(i::Handle obj) { return reinterpret_cast(i::HeapObject::cast(*obj)->GetIsolate()) ->GetCurrentContext(); } class InternalEscapableScope : public v8::EscapableHandleScope { public: explicit inline InternalEscapableScope(i::Isolate* isolate) : v8::EscapableHandleScope(reinterpret_cast(isolate)) {} }; class CallDepthScope { public: explicit CallDepthScope(i::Isolate* isolate, Local context, bool do_callback) : isolate_(isolate), context_(context), escaped_(false), do_callback_(do_callback) { // TODO(dcarney): remove this when blink stops crashing. DCHECK(!isolate_->external_caught_exception()); isolate_->handle_scope_implementer()->IncrementCallDepth(); if (!context_.IsEmpty()) context_->Enter(); } ~CallDepthScope() { if (!context_.IsEmpty()) context_->Exit(); if (!escaped_) isolate_->handle_scope_implementer()->DecrementCallDepth(); if (do_callback_) isolate_->FireCallCompletedCallback(); } void Escape() { DCHECK(!escaped_); escaped_ = true; auto handle_scope_implementer = isolate_->handle_scope_implementer(); handle_scope_implementer->DecrementCallDepth(); bool call_depth_is_zero = handle_scope_implementer->CallDepthIsZero(); isolate_->OptionalRescheduleException(call_depth_is_zero); } private: i::Isolate* const isolate_; Local context_; bool escaped_; bool do_callback_; }; } // namespace static ScriptOrigin GetScriptOriginForScript(i::Isolate* isolate, i::Handle script) { i::Handle scriptName(i::Script::GetNameOrSourceURL(script)); i::Handle source_map_url(script->source_mapping_url(), isolate); v8::Isolate* v8_isolate = reinterpret_cast(script->GetIsolate()); ScriptOriginOptions options(script->origin_options()); v8::ScriptOrigin origin( Utils::ToLocal(scriptName), v8::Integer::New(v8_isolate, script->line_offset()->value()), v8::Integer::New(v8_isolate, script->column_offset()->value()), v8::Boolean::New(v8_isolate, options.IsSharedCrossOrigin()), v8::Integer::New(v8_isolate, script->id()->value()), v8::Boolean::New(v8_isolate, options.IsEmbedderDebugScript()), Utils::ToLocal(source_map_url), v8::Boolean::New(v8_isolate, options.IsOpaque())); return origin; } // --- 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::Isolate* isolate = i::Isolate::Current(); char last_few_messages[Heap::kTraceRingBufferSize + 1]; char js_stacktrace[Heap::kStacktraceBufferSize + 1]; memset(last_few_messages, 0, Heap::kTraceRingBufferSize + 1); memset(js_stacktrace, 0, Heap::kStacktraceBufferSize + 1); 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_space_size; heap_stats.old_space_size = &old_space_size; intptr_t old_space_capacity; heap_stats.old_space_capacity = &old_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 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; heap_stats.last_few_messages = last_few_messages; heap_stats.js_stacktrace = js_stacktrace; int end_marker; heap_stats.end_marker = &end_marker; 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); char* first_newline = strchr(last_few_messages, '\n'); if (first_newline == NULL || first_newline[1] == '\0') first_newline = last_few_messages; PrintF("\n<--- Last few GCs --->\n%s\n", first_newline); PrintF("\n<--- JS stacktrace --->\n%s\n", js_stacktrace); } 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; } void V8::SetNativesDataBlob(StartupData* natives_blob) { i::V8::SetNativesBlob(natives_blob); } void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) { i::V8::SetSnapshotBlob(snapshot_blob); } bool RunExtraCode(Isolate* isolate, Local context, const char* utf8_source) { // Run custom script if provided. base::ElapsedTimer timer; timer.Start(); TryCatch try_catch(isolate); Local source_string; if (!String::NewFromUtf8(isolate, utf8_source, NewStringType::kNormal) .ToLocal(&source_string)) { return false; } Local resource_name = String::NewFromUtf8(isolate, "", NewStringType::kNormal) .ToLocalChecked(); ScriptOrigin origin(resource_name); ScriptCompiler::Source source(source_string, origin); Local