// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. #ifndef INTERNAL_H_ #define INTERNAL_H_ #include #include #include #include #include "buffer.h" #include "deno.h" #include "v8/include/v8.h" #include "v8/src/base/logging.h" namespace deno { struct ModuleInfo { bool main; std::string name; v8::Persistent handle; std::vector import_specifiers; ModuleInfo(v8::Isolate* isolate, v8::Local module, bool main_, const char* name_, std::vector import_specifiers_) : main(main_), name(name_), import_specifiers(import_specifiers_) { handle.Reset(isolate, module); } }; // deno_s = Wrapped Isolate. class DenoIsolate { public: explicit DenoIsolate(deno_config config) : isolate_(nullptr), locker_(nullptr), shared_(config.shared), current_args_(nullptr), snapshot_creator_(nullptr), global_import_buf_ptr_(nullptr), recv_cb_(config.recv_cb), user_data_(nullptr), resolve_cb_(nullptr), next_dyn_import_id_(0), dyn_import_cb_(config.dyn_import_cb), has_snapshotted_(false) { if (config.load_snapshot.data_ptr) { snapshot_.data = reinterpret_cast(config.load_snapshot.data_ptr); snapshot_.raw_size = static_cast(config.load_snapshot.data_len); } } ~DenoIsolate() { last_exception_handle_.Reset(); shared_ab_.Reset(); if (locker_) { delete locker_; } if (snapshot_creator_) { // TODO(ry) V8 has a strange assert which prevents a SnapshotCreator from // being deallocated if it hasn't created a snapshot yet. // https://github.com/v8/v8/blob/73212783fbd534fac76cc4b66aac899c13f71fc8/src/api.cc#L603 // If that assert is removed, this if guard could be removed. // WARNING: There may be false positive LSAN errors here. if (has_snapshotted_) { delete snapshot_creator_; } } else { isolate_->Dispose(); } } static inline DenoIsolate* FromIsolate(v8::Isolate* isolate) { return static_cast(isolate->GetData(0)); } void AddIsolate(v8::Isolate* isolate); deno_mod RegisterModule(bool main, const char* name, const char* source); void ClearModules(); ModuleInfo* GetModuleInfo(deno_mod id) { if (id == 0) { return nullptr; } auto it = mods_.find(id); if (it != mods_.end()) { return &it->second; } else { return nullptr; } } v8::Isolate* isolate_; v8::Locker* locker_; deno_buf shared_; const v8::FunctionCallbackInfo* current_args_; v8::SnapshotCreator* snapshot_creator_; void* global_import_buf_ptr_; deno_recv_cb recv_cb_; void* user_data_; std::map mods_; std::map mods_by_name_; deno_resolve_cb resolve_cb_; deno_dyn_import_id next_dyn_import_id_; deno_dyn_import_cb dyn_import_cb_; std::map> dyn_import_map_; v8::Persistent context_; std::map> pending_promise_map_; std::string last_exception_; v8::Persistent last_exception_handle_; v8::Persistent recv_; v8::StartupData snapshot_; v8::Persistent global_import_buf_; v8::Persistent shared_ab_; bool has_snapshotted_; }; class UserDataScope { DenoIsolate* deno_; void* prev_data_; void* data_; // Not necessary; only for sanity checking. public: UserDataScope(DenoIsolate* deno, void* data) : deno_(deno), data_(data) { CHECK(deno->user_data_ == nullptr || deno->user_data_ == data_); prev_data_ = deno->user_data_; deno->user_data_ = data; } ~UserDataScope() { CHECK(deno_->user_data_ == data_); deno_->user_data_ = prev_data_; } }; struct InternalFieldData { uint32_t data; }; static inline v8::Local v8_str(const char* x) { return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), x, v8::NewStringType::kNormal) .ToLocalChecked(); } void Print(const v8::FunctionCallbackInfo& args); void Recv(const v8::FunctionCallbackInfo& args); void Send(const v8::FunctionCallbackInfo& args); void EvalContext(const v8::FunctionCallbackInfo& args); void ErrorToJSON(const v8::FunctionCallbackInfo& args); void Shared(v8::Local property, const v8::PropertyCallbackInfo& info); void MessageCallback(v8::Local message, v8::Local data); void QueueMicrotask(const v8::FunctionCallbackInfo& args); static intptr_t external_references[] = { reinterpret_cast(Print), reinterpret_cast(Recv), reinterpret_cast(Send), reinterpret_cast(EvalContext), reinterpret_cast(ErrorToJSON), reinterpret_cast(Shared), reinterpret_cast(MessageCallback), reinterpret_cast(QueueMicrotask), 0}; static const deno_buf empty_buf = {nullptr, 0}; static const deno_snapshot empty_snapshot = {nullptr, 0}; Deno* NewFromSnapshot(void* user_data, deno_recv_cb cb); void InitializeContext(v8::Isolate* isolate, v8::Local context); void DeserializeInternalFields(v8::Local holder, int index, v8::StartupData payload, void* data); v8::StartupData SerializeInternalFields(v8::Local holder, int index, void* data); v8::Local ImportBuf(DenoIsolate* d, deno_buf buf); bool Execute(v8::Local context, const char* js_filename, const char* js_source); bool ExecuteMod(v8::Local context, const char* js_filename, const char* js_source, bool resolve_only); } // namespace deno extern "C" { // This is just to workaround the linker. struct deno_s { deno::DenoIsolate isolate; }; } #endif // INTERNAL_H_