diff --git a/BUILD.gn b/BUILD.gn index e4ce1c9b58..b70db0f058 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -211,12 +211,12 @@ v8_executable("test_cc") { static_library("libdeno") { complete_static_lib = true sources = [ + "libdeno/api.cc", "libdeno/binding.cc", "libdeno/deno.h", "libdeno/file_util.cc", "libdeno/file_util.h", "libdeno/internal.h", - "libdeno/new.cc", ] public_deps = [ "third_party/v8:v8_monolith", diff --git a/libdeno/api.cc b/libdeno/api.cc new file mode 100644 index 0000000000..e01f95e82a --- /dev/null +++ b/libdeno/api.cc @@ -0,0 +1,162 @@ +// Copyright 2018 the Deno authors. All rights reserved. MIT license. +#include +#include +#include +#include + +#include "third_party/v8/include/libplatform/libplatform.h" +#include "third_party/v8/include/v8.h" +#include "third_party/v8/src/base/logging.h" + +#include "deno.h" +#include "internal.h" + +extern "C" { + +Deno* deno_new(deno_buf snapshot, deno_recv_cb cb) { + deno::DenoIsolate* d = new deno::DenoIsolate(snapshot, cb); + v8::Isolate::CreateParams params; + params.array_buffer_allocator = + v8::ArrayBuffer::Allocator::NewDefaultAllocator(); + params.external_references = deno::external_references; + + if (snapshot.data_ptr) { + params.snapshot_blob = &d->snapshot_; + } + + v8::Isolate* isolate = v8::Isolate::New(params); + d->AddIsolate(isolate); + + v8::Locker locker(isolate); + v8::Isolate::Scope isolate_scope(isolate); + { + v8::HandleScope handle_scope(isolate); + auto context = + v8::Context::New(isolate, nullptr, v8::MaybeLocal(), + v8::MaybeLocal(), + v8::DeserializeInternalFieldsCallback( + deno::DeserializeInternalFields, nullptr)); + d->context_.Reset(isolate, context); + } + + return reinterpret_cast(d); +} + +deno::DenoIsolate* unwrap(Deno* d_) { + return reinterpret_cast(d_); +} + +void deno_init() { + // v8::V8::InitializeICUDefaultLocation(argv[0]); + // v8::V8::InitializeExternalStartupData(argv[0]); + auto* p = v8::platform::CreateDefaultPlatform(); + v8::V8::InitializePlatform(p); + v8::V8::Initialize(); +} + +const char* deno_v8_version() { return v8::V8::GetVersion(); } + +void deno_set_v8_flags(int* argc, char** argv) { + v8::V8::SetFlagsFromCommandLine(argc, argv, true); +} + +const char* deno_last_exception(Deno* d_) { + auto* d = unwrap(d_); + return d->last_exception_.c_str(); +} + +int deno_execute(Deno* d_, void* user_data_, const char* js_filename, + const char* js_source) { + auto* d = unwrap(d_); + deno::UserDataScope user_data_scope(d, user_data_); + auto* isolate = d->isolate_; + v8::Locker locker(isolate); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + auto context = d->context_.Get(d->isolate_); + return deno::Execute(context, js_filename, js_source) ? 1 : 0; +} + +int deno_respond(Deno* d_, void* user_data_, int32_t req_id, deno_buf buf) { + auto* d = unwrap(d_); + if (d->current_args_ != nullptr) { + // Synchronous response. + auto ab = deno::ImportBuf(d, buf); + d->current_args_->GetReturnValue().Set(ab); + d->current_args_ = nullptr; + return 0; + } + + // Asynchronous response. + deno::UserDataScope user_data_scope(d, user_data_); + v8::Locker locker(d->isolate_); + v8::Isolate::Scope isolate_scope(d->isolate_); + v8::HandleScope handle_scope(d->isolate_); + + auto context = d->context_.Get(d->isolate_); + v8::Context::Scope context_scope(context); + + v8::TryCatch try_catch(d->isolate_); + + deno::DeleteDataRef(d, req_id); + + auto recv_ = d->recv_.Get(d->isolate_); + if (recv_.IsEmpty()) { + d->last_exception_ = "libdeno.recv_ has not been called."; + return 1; + } + + v8::Local args[1]; + args[0] = deno::ImportBuf(d, buf); + recv_->Call(context->Global(), 1, args); + + if (try_catch.HasCaught()) { + deno::HandleException(context, try_catch.Exception()); + return 1; + } + + return 0; +} + +void deno_check_promise_errors(Deno* d_) { + auto* d = unwrap(d_); + if (d->pending_promise_events_ > 0) { + auto* isolate = d->isolate_; + v8::Locker locker(isolate); + v8::Isolate::Scope isolate_scope(isolate); + v8::HandleScope handle_scope(isolate); + + auto context = d->context_.Get(d->isolate_); + v8::Context::Scope context_scope(context); + + v8::TryCatch try_catch(d->isolate_); + auto promise_error_examiner_ = d->promise_error_examiner_.Get(d->isolate_); + if (promise_error_examiner_.IsEmpty()) { + d->last_exception_ = + "libdeno.setPromiseErrorExaminer has not been called."; + return; + } + v8::Local args[0]; + auto result = promise_error_examiner_->Call(context->Global(), 0, args); + if (try_catch.HasCaught()) { + deno::HandleException(context, try_catch.Exception()); + } + d->pending_promise_events_ = 0; // reset + if (!result->BooleanValue(context).FromJust()) { + // Has uncaught promise reject error, exiting... + exit(1); + } + } +} + +void deno_delete(Deno* d_) { + deno::DenoIsolate* d = reinterpret_cast(d_); + d->isolate_->Dispose(); + delete d; +} + +void deno_terminate_execution(Deno* d_) { + deno::DenoIsolate* d = reinterpret_cast(d_); + d->isolate_->TerminateExecution(); +} +} diff --git a/libdeno/binding.cc b/libdeno/binding.cc index 3a3f171e63..9fca3814c7 100644 --- a/libdeno/binding.cc +++ b/libdeno/binding.cc @@ -5,7 +5,6 @@ #include #include -#include "third_party/v8/include/libplatform/libplatform.h" #include "third_party/v8/include/v8.h" #include "third_party/v8/src/base/logging.h" @@ -16,21 +15,36 @@ namespace deno { -Deno* FromIsolate(v8::Isolate* isolate) { - return static_cast(isolate->GetData(0)); +std::vector deserialized_data; + +void DeserializeInternalFields(v8::Local holder, int index, + v8::StartupData payload, void* data) { + DCHECK_EQ(data, nullptr); + if (payload.raw_size == 0) { + holder->SetAlignedPointerInInternalField(index, nullptr); + return; + } + InternalFieldData* embedder_field = new InternalFieldData{0}; + memcpy(embedder_field, payload.data, payload.raw_size); + holder->SetAlignedPointerInInternalField(index, embedder_field); + deserialized_data.push_back(embedder_field); } -void AddDataRef(Deno* d, int32_t req_id, v8::Local data_v) { - d->async_data_map.emplace(std::piecewise_construct, std::make_tuple(req_id), - std::make_tuple(d->isolate, data_v)); +DenoIsolate* FromIsolate(v8::Isolate* isolate) { + return static_cast(isolate->GetData(0)); } -void DeleteDataRef(Deno* d, int32_t req_id) { +void AddDataRef(DenoIsolate* d, int32_t req_id, v8::Local data_v) { + d->async_data_map_.emplace(std::piecewise_construct, std::make_tuple(req_id), + std::make_tuple(d->isolate_, data_v)); +} + +void DeleteDataRef(DenoIsolate* d, int32_t req_id) { // Delete persistent reference to data ArrayBuffer. - auto it = d->async_data_map.find(req_id); - if (it != d->async_data_map.end()) { + auto it = d->async_data_map_.find(req_id); + if (it != d->async_data_map_.end()) { it->second.Reset(); - d->async_data_map.erase(it); + d->async_data_map_.erase(it); } } @@ -49,7 +63,7 @@ void HandleExceptionStr(v8::Local context, v8::Local exception, std::string* exception_str) { auto* isolate = context->GetIsolate(); - Deno* d = FromIsolate(isolate); + DenoIsolate* d = FromIsolate(isolate); v8::HandleScope handle_scope(isolate); v8::Context::Scope context_scope(context); @@ -61,10 +75,10 @@ void HandleExceptionStr(v8::Local context, auto column = v8::Integer::New(isolate, message->GetStartColumn(context).FromJust()); - auto global_error_handler = d->global_error_handler.Get(isolate); + auto global_error_handler_ = d->global_error_handler_.Get(isolate); - if (!global_error_handler.IsEmpty()) { - // global_error_handler is set so we try to handle the exception in + if (!global_error_handler_.IsEmpty()) { + // global_error_handler_ is set so we try to handle the exception in // javascript. v8::Local args[5]; args[0] = exception->ToString(context).ToLocalChecked(); @@ -72,7 +86,7 @@ void HandleExceptionStr(v8::Local context, args[2] = line; args[3] = column; args[4] = exception; - global_error_handler->Call(context->Global(), 5, args); + global_error_handler_->Call(context->Global(), 5, args); /* message, source, lineno, colno, error */ return; @@ -81,7 +95,7 @@ void HandleExceptionStr(v8::Local context, char buf[12 * 1024]; if (!stack_trace.IsEmpty()) { // No javascript error handler, but we do have a stack trace. Format it - // into a string and add to last_exception. + // into a string and add to last_exception_. std::string msg; v8::String::Utf8Value exceptionStr(isolate, exception); msg += ToCString(exceptionStr); @@ -98,7 +112,7 @@ void HandleExceptionStr(v8::Local context, *exception_str += msg; } else { // No javascript error handler, no stack trace. Format the little info we - // have into a string and add to last_exception. + // have into a string and add to last_exception_. v8::String::Utf8Value exceptionStr(isolate, exception); v8::String::Utf8Value script_name(isolate, message->GetScriptResourceName()); @@ -113,11 +127,11 @@ void HandleExceptionStr(v8::Local context, void HandleException(v8::Local context, v8::Local exception) { v8::Isolate* isolate = context->GetIsolate(); - Deno* d = FromIsolate(isolate); + DenoIsolate* d = FromIsolate(isolate); std::string exception_str; HandleExceptionStr(context, exception, &exception_str); if (d != nullptr) { - d->last_exception = exception_str; + d->last_exception_ = exception_str; } else { std::cerr << "Pre-Deno Exception " << exception_str << std::endl; exit(1); @@ -139,16 +153,16 @@ const char* PromiseRejectStr(enum v8::PromiseRejectEvent e) { void PromiseRejectCallback(v8::PromiseRejectMessage promise_reject_message) { auto* isolate = v8::Isolate::GetCurrent(); - Deno* d = static_cast(isolate->GetData(0)); - DCHECK_EQ(d->isolate, isolate); - v8::HandleScope handle_scope(d->isolate); + DenoIsolate* d = static_cast(isolate->GetData(0)); + DCHECK_EQ(d->isolate_, isolate); + v8::HandleScope handle_scope(d->isolate_); auto exception = promise_reject_message.GetValue(); - auto context = d->context.Get(d->isolate); + auto context = d->context_.Get(d->isolate_); auto promise = promise_reject_message.GetPromise(); auto event = promise_reject_message.GetEvent(); v8::Context::Scope context_scope(context); - auto promise_reject_handler = d->promise_reject_handler.Get(isolate); + auto promise_reject_handler = d->promise_reject_handler_.Get(isolate); if (!promise_reject_handler.IsEmpty()) { v8::Local args[3]; @@ -156,22 +170,22 @@ void PromiseRejectCallback(v8::PromiseRejectMessage promise_reject_message) { args[2] = promise; /* error, event, promise */ if (event == v8::PromiseRejectEvent::kPromiseRejectWithNoHandler) { - d->pending_promise_events++; + d->pending_promise_events_++; // exception only valid for kPromiseRejectWithNoHandler args[0] = exception; } else if (event == v8::PromiseRejectEvent::kPromiseHandlerAddedAfterReject) { - d->pending_promise_events--; // unhandled event cancelled - if (d->pending_promise_events < 0) { - d->pending_promise_events = 0; + d->pending_promise_events_--; // unhandled event cancelled + if (d->pending_promise_events_ < 0) { + d->pending_promise_events_ = 0; } // Placeholder, not actually used args[0] = v8_str("Promise handler added"); } else if (event == v8::PromiseRejectEvent::kPromiseResolveAfterResolved) { - d->pending_promise_events++; + d->pending_promise_events_++; args[0] = v8_str("Promise resolved after resolved"); } else if (event == v8::PromiseRejectEvent::kPromiseRejectAfterResolved) { - d->pending_promise_events++; + d->pending_promise_events_++; args[0] = v8_str("Promise rejected after resolved"); } promise_reject_handler->Call(context->Global(), 3, args); @@ -183,8 +197,8 @@ void Print(const v8::FunctionCallbackInfo& args) { CHECK_GE(args.Length(), 1); CHECK_LE(args.Length(), 2); auto* isolate = args.GetIsolate(); - Deno* d = static_cast(isolate->GetData(0)); - auto context = d->context.Get(d->isolate); + DenoIsolate* d = FromIsolate(isolate); + auto context = d->context_.Get(d->isolate_); v8::HandleScope handle_scope(isolate); v8::String::Utf8Value str(isolate, args[0]); bool is_err = @@ -194,7 +208,7 @@ void Print(const v8::FunctionCallbackInfo& args) { stream << cstr << std::endl; } -static v8::Local ImportBuf(Deno* d, deno_buf buf) { +v8::Local ImportBuf(DenoIsolate* d, deno_buf buf) { if (buf.alloc_ptr == nullptr) { // If alloc_ptr isn't set, we memcpy. // This is currently used for flatbuffers created in Rust. @@ -207,28 +221,28 @@ static v8::Local ImportBuf(Deno* d, deno_buf buf) { void* data; if (buf.data_len > GLOBAL_IMPORT_BUF_SIZE) { // Simple case. We allocate a new ArrayBuffer for this. - ab = v8::ArrayBuffer::New(d->isolate, buf.data_len); + ab = v8::ArrayBuffer::New(d->isolate_, buf.data_len); data = ab->GetContents().Data(); } else { // Fast case. We reuse the global ArrayBuffer. - if (d->global_import_buf.IsEmpty()) { + if (d->global_import_buf_.IsEmpty()) { // Lazily initialize it. - DCHECK_EQ(d->global_import_buf_ptr, nullptr); - ab = v8::ArrayBuffer::New(d->isolate, GLOBAL_IMPORT_BUF_SIZE); - d->global_import_buf.Reset(d->isolate, ab); - d->global_import_buf_ptr = ab->GetContents().Data(); + DCHECK_EQ(d->global_import_buf_ptr_, nullptr); + ab = v8::ArrayBuffer::New(d->isolate_, GLOBAL_IMPORT_BUF_SIZE); + d->global_import_buf_.Reset(d->isolate_, ab); + d->global_import_buf_ptr_ = ab->GetContents().Data(); } else { - DCHECK(d->global_import_buf_ptr); - ab = d->global_import_buf.Get(d->isolate); + DCHECK(d->global_import_buf_ptr_); + ab = d->global_import_buf_.Get(d->isolate_); } - data = d->global_import_buf_ptr; + data = d->global_import_buf_ptr_; } memcpy(data, buf.data_ptr, buf.data_len); auto view = v8::Uint8Array::New(ab, 0, buf.data_len); return view; } else { auto ab = v8::ArrayBuffer::New( - d->isolate, reinterpret_cast(buf.alloc_ptr), buf.alloc_len, + d->isolate_, reinterpret_cast(buf.alloc_ptr), buf.alloc_len, v8::ArrayBufferCreationMode::kInternalized); auto view = v8::Uint8Array::New(ab, buf.data_ptr - buf.alloc_ptr, buf.data_len); @@ -248,16 +262,16 @@ static deno_buf GetContents(v8::Isolate* isolate, return buf; } -// Sets the recv callback. +// Sets the recv_ callback. void Recv(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - Deno* d = reinterpret_cast(isolate->GetData(0)); - DCHECK_EQ(d->isolate, isolate); + DenoIsolate* d = FromIsolate(isolate); + DCHECK_EQ(d->isolate_, isolate); v8::HandleScope handle_scope(isolate); - if (!d->recv.IsEmpty()) { - isolate->ThrowException(v8_str("libdeno.recv already called.")); + if (!d->recv_.IsEmpty()) { + isolate->ThrowException(v8_str("libdeno.recv_ already called.")); return; } @@ -265,19 +279,19 @@ void Recv(const v8::FunctionCallbackInfo& args) { CHECK(v->IsFunction()); v8::Local func = v8::Local::Cast(v); - d->recv.Reset(isolate, func); + d->recv_.Reset(isolate, func); } void Send(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - Deno* d = static_cast(isolate->GetData(0)); - DCHECK_EQ(d->isolate, isolate); + DenoIsolate* d = FromIsolate(isolate); + DCHECK_EQ(d->isolate_, isolate); - v8::Locker locker(d->isolate); + v8::Locker locker(d->isolate_); v8::EscapableHandleScope handle_scope(isolate); - CHECK_EQ(d->currentArgs, nullptr); // libdeno.send re-entry forbidden. - int32_t req_id = d->next_req_id++; + CHECK_EQ(d->current_args_, nullptr); // libdeno.send re-entry forbidden. + int32_t req_id = d->next_req_id_++; v8::Local control_v = args[0]; CHECK(control_v->IsArrayBufferView()); @@ -294,16 +308,16 @@ void Send(const v8::FunctionCallbackInfo& args) { CHECK_EQ(args.Length(), 1); } - DCHECK_EQ(d->currentArgs, nullptr); - d->currentArgs = &args; + DCHECK_EQ(d->current_args_, nullptr); + d->current_args_ = &args; - d->cb(d->user_data, req_id, control, data); + d->cb_(d->user_data_, req_id, control, data); - if (d->currentArgs == nullptr) { + if (d->current_args_ == nullptr) { // This indicates that deno_repond() was called already. } else { // Asynchronous. - d->currentArgs = nullptr; + d->current_args_ = nullptr; // If the data ArrayBuffer was given, we must maintain a strong reference // to it until deno_respond is called. if (!data_v.IsEmpty()) { @@ -315,12 +329,12 @@ void Send(const v8::FunctionCallbackInfo& args) { // Sets the global error handler. void SetGlobalErrorHandler(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - Deno* d = reinterpret_cast(isolate->GetData(0)); - DCHECK_EQ(d->isolate, isolate); + DenoIsolate* d = FromIsolate(isolate); + DCHECK_EQ(d->isolate_, isolate); v8::HandleScope handle_scope(isolate); - if (!d->global_error_handler.IsEmpty()) { + if (!d->global_error_handler_.IsEmpty()) { isolate->ThrowException( v8_str("libdeno.setGlobalErrorHandler already called.")); return; @@ -330,18 +344,18 @@ void SetGlobalErrorHandler(const v8::FunctionCallbackInfo& args) { CHECK(v->IsFunction()); v8::Local func = v8::Local::Cast(v); - d->global_error_handler.Reset(isolate, func); + d->global_error_handler_.Reset(isolate, func); } // Sets the promise uncaught reject handler void SetPromiseRejectHandler(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - Deno* d = reinterpret_cast(isolate->GetData(0)); - DCHECK_EQ(d->isolate, isolate); + DenoIsolate* d = FromIsolate(isolate); + DCHECK_EQ(d->isolate_, isolate); v8::HandleScope handle_scope(isolate); - if (!d->promise_reject_handler.IsEmpty()) { + if (!d->promise_reject_handler_.IsEmpty()) { isolate->ThrowException( v8_str("libdeno.setPromiseRejectHandler already called.")); return; @@ -351,18 +365,18 @@ void SetPromiseRejectHandler(const v8::FunctionCallbackInfo& args) { CHECK(v->IsFunction()); v8::Local func = v8::Local::Cast(v); - d->promise_reject_handler.Reset(isolate, func); + d->promise_reject_handler_.Reset(isolate, func); } // Sets the promise uncaught reject handler void SetPromiseErrorExaminer(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); - Deno* d = reinterpret_cast(isolate->GetData(0)); - DCHECK_EQ(d->isolate, isolate); + DenoIsolate* d = FromIsolate(isolate); + DCHECK_EQ(d->isolate_, isolate); v8::HandleScope handle_scope(isolate); - if (!d->promise_error_examiner.IsEmpty()) { + if (!d->promise_error_examiner_.IsEmpty()) { isolate->ThrowException( v8_str("libdeno.setPromiseErrorExaminer already called.")); return; @@ -372,7 +386,7 @@ void SetPromiseErrorExaminer(const v8::FunctionCallbackInfo& args) { CHECK(v->IsFunction()); v8::Local func = v8::Local::Cast(v); - d->promise_error_examiner.Reset(isolate, func); + d->promise_error_examiner_.Reset(isolate, func); } bool ExecuteV8StringSource(v8::Local context, @@ -502,145 +516,16 @@ void InitializeContext(v8::Isolate* isolate, v8::Local context, } } -void AddIsolate(Deno* d, v8::Isolate* isolate) { - d->pending_promise_events = 0; - d->next_req_id = 0; - d->global_import_buf_ptr = nullptr; - d->isolate = isolate; +void DenoIsolate::AddIsolate(v8::Isolate* isolate) { + isolate_ = isolate; // Leaving this code here because it will probably be useful later on, but // disabling it now as I haven't got tests for the desired behavior. // d->isolate->SetCaptureStackTraceForUncaughtExceptions(true); // d->isolate->SetAbortOnUncaughtExceptionCallback(AbortOnUncaughtExceptionCallback); // d->isolate->AddMessageListener(MessageCallback2); // d->isolate->SetFatalErrorHandler(FatalErrorCallback2); - d->isolate->SetPromiseRejectCallback(deno::PromiseRejectCallback); - d->isolate->SetData(0, d); + isolate_->SetPromiseRejectCallback(deno::PromiseRejectCallback); + isolate_->SetData(0, this); } -class UserDataScope { - Deno* deno; - void* prev_data; - void* data; // Not necessary; only for sanity checking. - - public: - UserDataScope(Deno* 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; - } -}; - } // namespace deno - -extern "C" { - -void deno_init() { - // v8::V8::InitializeICUDefaultLocation(argv[0]); - // v8::V8::InitializeExternalStartupData(argv[0]); - auto* p = v8::platform::CreateDefaultPlatform(); - v8::V8::InitializePlatform(p); - v8::V8::Initialize(); -} - -const char* deno_v8_version() { return v8::V8::GetVersion(); } - -void deno_set_v8_flags(int* argc, char** argv) { - v8::V8::SetFlagsFromCommandLine(argc, argv, true); -} - -const char* deno_last_exception(Deno* d) { return d->last_exception.c_str(); } - -int deno_execute(Deno* d, void* user_data, const char* js_filename, - const char* js_source) { - deno::UserDataScope user_data_scope(d, user_data); - auto* isolate = d->isolate; - v8::Locker locker(isolate); - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - auto context = d->context.Get(d->isolate); - return deno::Execute(context, js_filename, js_source) ? 1 : 0; -} - -int deno_respond(Deno* d, void* user_data, int32_t req_id, deno_buf buf) { - if (d->currentArgs != nullptr) { - // Synchronous response. - auto ab = deno::ImportBuf(d, buf); - d->currentArgs->GetReturnValue().Set(ab); - d->currentArgs = nullptr; - return 0; - } - - // Asynchronous response. - deno::UserDataScope user_data_scope(d, user_data); - v8::Locker locker(d->isolate); - v8::Isolate::Scope isolate_scope(d->isolate); - v8::HandleScope handle_scope(d->isolate); - - auto context = d->context.Get(d->isolate); - v8::Context::Scope context_scope(context); - - v8::TryCatch try_catch(d->isolate); - - deno::DeleteDataRef(d, req_id); - - auto recv = d->recv.Get(d->isolate); - if (recv.IsEmpty()) { - d->last_exception = "libdeno.recv has not been called."; - return 1; - } - - v8::Local args[1]; - args[0] = deno::ImportBuf(d, buf); - recv->Call(context->Global(), 1, args); - - if (try_catch.HasCaught()) { - deno::HandleException(context, try_catch.Exception()); - return 1; - } - - return 0; -} - -void deno_check_promise_errors(Deno* d) { - if (d->pending_promise_events > 0) { - auto* isolate = d->isolate; - v8::Locker locker(isolate); - v8::Isolate::Scope isolate_scope(isolate); - v8::HandleScope handle_scope(isolate); - - auto context = d->context.Get(d->isolate); - v8::Context::Scope context_scope(context); - - v8::TryCatch try_catch(d->isolate); - auto promise_error_examiner = d->promise_error_examiner.Get(d->isolate); - if (promise_error_examiner.IsEmpty()) { - d->last_exception = - "libdeno.setPromiseErrorExaminer has not been called."; - return; - } - v8::Local args[0]; - auto result = promise_error_examiner->Call(context->Global(), 0, args); - if (try_catch.HasCaught()) { - deno::HandleException(context, try_catch.Exception()); - } - d->pending_promise_events = 0; // reset - if (!result->BooleanValue(context).FromJust()) { - // Has uncaught promise reject error, exiting... - exit(1); - } - } -} - -void deno_delete(Deno* d) { - d->isolate->Dispose(); - delete d; -} - -void deno_terminate_execution(Deno* d) { d->isolate->TerminateExecution(); } - -} // extern "C" diff --git a/libdeno/deno.h b/libdeno/deno.h index e93b2e7f46..f833bd5417 100644 --- a/libdeno/deno.h +++ b/libdeno/deno.h @@ -17,7 +17,6 @@ typedef struct { size_t data_len; // Length of logical contents. } deno_buf; -struct deno_s; typedef struct deno_s Deno; // A callback to receive a message from a libdeno.send() javascript call. diff --git a/libdeno/internal.h b/libdeno/internal.h index be96510104..d71b36048e 100644 --- a/libdeno/internal.h +++ b/libdeno/internal.h @@ -6,32 +6,67 @@ #include #include "deno.h" #include "third_party/v8/include/v8.h" - -extern "C" { -// deno_s = Wrapped Isolate. -struct deno_s { - v8::Isolate* isolate; - const v8::FunctionCallbackInfo* currentArgs; - std::string last_exception; - v8::Persistent recv; - v8::Persistent global_error_handler; - v8::Persistent promise_reject_handler; - v8::Persistent promise_error_examiner; - v8::StartupData snapshot; - v8::Persistent global_import_buf; - void* global_import_buf_ptr; - - int32_t pending_promise_events; - v8::Persistent context; - std::map> async_data_map; - deno_recv_cb cb; - int32_t next_req_id; - void* user_data; -}; -} +#include "third_party/v8/src/base/logging.h" namespace deno { +// deno_s = Wrapped Isolate. +class DenoIsolate { + public: + DenoIsolate(deno_buf snapshot, deno_recv_cb cb) + : isolate_(nullptr), + current_args_(nullptr), + global_import_buf_ptr_(nullptr), + pending_promise_events_(0), + cb_(cb), + next_req_id_(0), + user_data_(nullptr) { + if (snapshot.data_ptr) { + snapshot_.data = reinterpret_cast(snapshot.data_ptr); + snapshot_.raw_size = static_cast(snapshot.data_len); + } + } + + void AddIsolate(v8::Isolate* isolate); + + v8::Isolate* isolate_; + // Put v8::Isolate::CreateParams here.. + const v8::FunctionCallbackInfo* current_args_; + void* global_import_buf_ptr_; + int32_t pending_promise_events_; + deno_recv_cb cb_; + int32_t next_req_id_; + void* user_data_; + + v8::Persistent context_; + std::map> async_data_map_; + std::string last_exception_; + v8::Persistent recv_; + v8::Persistent global_error_handler_; + v8::Persistent promise_reject_handler_; + v8::Persistent promise_error_examiner_; + v8::StartupData snapshot_; + v8::Persistent global_import_buf_; +}; + +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; }; @@ -57,7 +92,26 @@ void InitializeContext(v8::Isolate* isolate, v8::Local context, const char* js_filename, const std::string& js_source, const std::string* source_map); -void AddIsolate(Deno* d, v8::Isolate* isolate); +void HandleException(v8::Local context, + v8::Local exception); + +void DeserializeInternalFields(v8::Local holder, int index, + v8::StartupData payload, void* data); + +v8::Local ImportBuf(DenoIsolate* d, deno_buf buf); + +void DeleteDataRef(DenoIsolate* d, int32_t req_id); + +bool Execute(v8::Local context, const char* js_filename, + const char* js_source); } // namespace deno + +extern "C" { +// This is just to workaround the linker. +struct deno_s { + deno::DenoIsolate isolate; +}; +} + #endif // INTERNAL_H_ diff --git a/libdeno/new.cc b/libdeno/new.cc deleted file mode 100644 index 5223f06041..0000000000 --- a/libdeno/new.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2018 the Deno authors. All rights reserved. MIT license. -#include -#include -#include -#include - -#include "third_party/v8/include/v8.h" -#include "third_party/v8/src/base/logging.h" - -#include "deno.h" -#include "internal.h" - -namespace deno { - -std::vector deserialized_data; - -void DeserializeInternalFields(v8::Local holder, int index, - v8::StartupData payload, void* data) { - DCHECK_EQ(data, nullptr); - if (payload.raw_size == 0) { - holder->SetAlignedPointerInInternalField(index, nullptr); - return; - } - InternalFieldData* embedder_field = new InternalFieldData{0}; - memcpy(embedder_field, payload.data, payload.raw_size); - holder->SetAlignedPointerInInternalField(index, embedder_field); - deserialized_data.push_back(embedder_field); -} - -} // namespace deno - -extern "C" { - -Deno* deno_new(deno_buf snapshot, deno_recv_cb cb) { - Deno* d = new Deno; - d->currentArgs = nullptr; - d->cb = cb; - d->user_data = nullptr; - v8::Isolate::CreateParams params; - params.array_buffer_allocator = - v8::ArrayBuffer::Allocator::NewDefaultAllocator(); - params.external_references = deno::external_references; - - if (snapshot.data_ptr) { - d->snapshot.data = reinterpret_cast(snapshot.data_ptr); - d->snapshot.raw_size = static_cast(snapshot.data_len); - params.snapshot_blob = &d->snapshot; - } - - v8::Isolate* isolate = v8::Isolate::New(params); - deno::AddIsolate(d, isolate); - - v8::Locker locker(isolate); - v8::Isolate::Scope isolate_scope(isolate); - { - v8::HandleScope handle_scope(isolate); - auto context = - v8::Context::New(isolate, nullptr, v8::MaybeLocal(), - v8::MaybeLocal(), - v8::DeserializeInternalFieldsCallback( - deno::DeserializeInternalFields, nullptr)); - d->context.Reset(d->isolate, context); - } - - return d; -} -}