// 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. // Defined when linking against shared lib on Windows. #if defined(USING_V8_SHARED) && !defined(V8_SHARED) #define V8_SHARED #endif #include #include #include #include #ifdef V8_SHARED #include #endif // V8_SHARED #ifndef V8_SHARED #include #include #endif // !V8_SHARED #ifdef V8_SHARED #include "include/v8-testing.h" #endif // V8_SHARED #if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE) #include "src/gdb-jit.h" #endif #ifdef ENABLE_VTUNE_JIT_INTERFACE #include "src/third_party/vtune/v8-vtune.h" #endif #include "src/d8.h" #include "include/libplatform/libplatform.h" #ifndef V8_SHARED #include "src/api.h" #include "src/base/cpu.h" #include "src/base/logging.h" #include "src/base/platform/platform.h" #include "src/base/sys-info.h" #include "src/basic-block-profiler.h" #include "src/snapshot/natives.h" #include "src/utils.h" #include "src/v8.h" #endif // !V8_SHARED #if !defined(_WIN32) && !defined(_WIN64) #include // NOLINT #else #include // NOLINT #if defined(_MSC_VER) #include // NOLINT #endif // defined(_MSC_VER) #endif // !defined(_WIN32) && !defined(_WIN64) #ifndef DCHECK #define DCHECK(condition) assert(condition) #endif #ifndef CHECK #define CHECK(condition) assert(condition) #endif namespace v8 { namespace { const int MB = 1024 * 1024; #ifndef V8_SHARED const int kMaxWorkers = 50; #endif class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: virtual void* Allocate(size_t length) { void* data = AllocateUninitialized(length); return data == NULL ? data : memset(data, 0, length); } virtual void* AllocateUninitialized(size_t length) { return malloc(length); } virtual void Free(void* data, size_t) { free(data); } }; class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator { public: void* Allocate(size_t length) override { size_t actual_length = length > 10 * MB ? 1 : length; void* data = AllocateUninitialized(actual_length); return data == NULL ? data : memset(data, 0, actual_length); } void* AllocateUninitialized(size_t length) override { return length > 10 * MB ? malloc(1) : malloc(length); } void Free(void* p, size_t) override { free(p); } }; #ifndef V8_SHARED // Predictable v8::Platform implementation. All background and foreground // tasks are run immediately, delayed tasks are not executed at all. class PredictablePlatform : public Platform { public: PredictablePlatform() {} void CallOnBackgroundThread(Task* task, ExpectedRuntime expected_runtime) override { task->Run(); delete task; } void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override { task->Run(); delete task; } void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task, double delay_in_seconds) override { delete task; } void CallIdleOnForegroundThread(v8::Isolate* isolate, IdleTask* task) override { UNREACHABLE(); } bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; } double MonotonicallyIncreasingTime() override { return synthetic_time_in_sec_ += 0.00001; } uint64_t AddTraceEvent(char phase, const uint8_t* categoryEnabledFlag, const char* name, uint64_t id, uint64_t bind_id, int numArgs, const char** argNames, const uint8_t* argTypes, const uint64_t* argValues, unsigned int flags) override { return 0; } void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag, const char* name, uint64_t handle) override {} const uint8_t* GetCategoryGroupEnabled(const char* name) override { static uint8_t no = 0; return &no; } const char* GetCategoryGroupName( const uint8_t* categoryEnabledFlag) override { static const char* dummy = "dummy"; return dummy; } private: double synthetic_time_in_sec_ = 0.0; DISALLOW_COPY_AND_ASSIGN(PredictablePlatform); }; #endif // !V8_SHARED v8::Platform* g_platform = NULL; static Local Throw(Isolate* isolate, const char* message) { return isolate->ThrowException( String::NewFromUtf8(isolate, message, NewStringType::kNormal) .ToLocalChecked()); } #ifndef V8_SHARED bool FindInObjectList(Local object, const Shell::ObjectList& list) { for (int i = 0; i < list.length(); ++i) { if (list[i]->StrictEquals(object)) { return true; } } return false; } Worker* GetWorkerFromInternalField(Isolate* isolate, Local object) { if (object->InternalFieldCount() != 1) { Throw(isolate, "this is not a Worker"); return NULL; } Worker* worker = static_cast(object->GetAlignedPointerFromInternalField(0)); if (worker == NULL) { Throw(isolate, "Worker is defunct because main thread is terminating"); return NULL; } return worker; } #endif // !V8_SHARED } // namespace class PerIsolateData { public: explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) { HandleScope scope(isolate); isolate->SetData(0, this); } ~PerIsolateData() { isolate_->SetData(0, NULL); // Not really needed, just to be sure... } inline static PerIsolateData* Get(Isolate* isolate) { return reinterpret_cast(isolate->GetData(0)); } class RealmScope { public: explicit RealmScope(PerIsolateData* data); ~RealmScope(); private: PerIsolateData* data_; }; private: friend class Shell; friend class RealmScope; Isolate* isolate_; int realm_count_; int realm_current_; int realm_switch_; Global* realms_; Global realm_shared_; int RealmIndexOrThrow(const v8::FunctionCallbackInfo& args, int arg_offset); int RealmFind(Local context); }; #ifndef V8_SHARED CounterMap* Shell::counter_map_; base::OS::MemoryMappedFile* Shell::counters_file_ = NULL; CounterCollection Shell::local_counters_; CounterCollection* Shell::counters_ = &local_counters_; base::LazyMutex Shell::context_mutex_; const base::TimeTicks Shell::kInitialTicks = base::TimeTicks::HighResolutionNow(); Global Shell::utility_context_; base::LazyMutex Shell::workers_mutex_; bool Shell::allow_new_workers_ = true; i::List Shell::workers_; i::List Shell::externalized_shared_contents_; #endif // !V8_SHARED Global Shell::evaluation_context_; ArrayBuffer::Allocator* Shell::array_buffer_allocator; ShellOptions Shell::options; base::OnceType Shell::quit_once_ = V8_ONCE_INIT; #ifndef V8_SHARED bool CounterMap::Match(void* key1, void* key2) { const char* name1 = reinterpret_cast(key1); const char* name2 = reinterpret_cast(key2); return strcmp(name1, name2) == 0; } #endif // !V8_SHARED // Converts a V8 value to a C string. const char* Shell::ToCString(const v8::String::Utf8Value& value) { return *value ? *value : ""; } ScriptCompiler::CachedData* CompileForCachedData( Local source, Local name, ScriptCompiler::CompileOptions compile_options) { int source_length = source->Length(); uint16_t* source_buffer = new uint16_t[source_length]; source->Write(source_buffer, 0, source_length); int name_length = 0; uint16_t* name_buffer = NULL; if (name->IsString()) { Local name_string = Local::Cast(name); name_length = name_string->Length(); name_buffer = new uint16_t[name_length]; name_string->Write(name_buffer, 0, name_length); } Isolate::CreateParams create_params; create_params.array_buffer_allocator = Shell::array_buffer_allocator; Isolate* temp_isolate = Isolate::New(create_params); ScriptCompiler::CachedData* result = NULL; { Isolate::Scope isolate_scope(temp_isolate); HandleScope handle_scope(temp_isolate); Context::Scope context_scope(Context::New(temp_isolate)); Local source_copy = v8::String::NewFromTwoByte(temp_isolate, source_buffer, v8::NewStringType::kNormal, source_length).ToLocalChecked(); Local name_copy; if (name_buffer) { name_copy = v8::String::NewFromTwoByte(temp_isolate, name_buffer, v8::NewStringType::kNormal, name_length).ToLocalChecked(); } else { name_copy = v8::Undefined(temp_isolate); } ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy)); if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source, compile_options).IsEmpty() && script_source.GetCachedData()) { int length = script_source.GetCachedData()->length; uint8_t* cache = new uint8_t[length]; memcpy(cache, script_source.GetCachedData()->data, length); result = new ScriptCompiler::CachedData( cache, length, ScriptCompiler::CachedData::BufferOwned); } } temp_isolate->Dispose(); delete[] source_buffer; delete[] name_buffer; return result; } // Compile a string within the current v8 context. MaybeLocal