0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-02-01 20:25:12 -05:00

libdeno: clean up

- Use a proper class for DenoIsolate.
- Move extern C stuff to api.cc
This commit is contained in:
Ryan Dahl 2018-10-23 23:58:20 -04:00
parent fd68f85ce8
commit 6afe94b3c8
6 changed files with 330 additions and 297 deletions

View file

@ -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",

162
libdeno/api.cc Normal file
View file

@ -0,0 +1,162 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#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::ObjectTemplate>(),
v8::MaybeLocal<v8::Value>(),
v8::DeserializeInternalFieldsCallback(
deno::DeserializeInternalFields, nullptr));
d->context_.Reset(isolate, context);
}
return reinterpret_cast<Deno*>(d);
}
deno::DenoIsolate* unwrap(Deno* d_) {
return reinterpret_cast<deno::DenoIsolate*>(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<v8::Value> 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<v8::Value> 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<deno::DenoIsolate*>(d_);
d->isolate_->Dispose();
delete d;
}
void deno_terminate_execution(Deno* d_) {
deno::DenoIsolate* d = reinterpret_cast<deno::DenoIsolate*>(d_);
d->isolate_->TerminateExecution();
}
}

View file

@ -5,7 +5,6 @@
#include <iostream>
#include <string>
#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<Deno*>(isolate->GetData(0));
std::vector<InternalFieldData*> deserialized_data;
void DeserializeInternalFields(v8::Local<v8::Object> 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<v8::Value> 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<DenoIsolate*>(isolate->GetData(0));
}
void DeleteDataRef(Deno* d, int32_t req_id) {
void AddDataRef(DenoIsolate* d, int32_t req_id, v8::Local<v8::Value> 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<v8::Context> context,
v8::Local<v8::Value> 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<v8::Context> 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<v8::Value> args[5];
args[0] = exception->ToString(context).ToLocalChecked();
@ -72,7 +86,7 @@ void HandleExceptionStr(v8::Local<v8::Context> 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<v8::Context> 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<v8::Context> 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<v8::Context> context,
void HandleException(v8::Local<v8::Context> context,
v8::Local<v8::Value> 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<Deno*>(isolate->GetData(0));
DCHECK_EQ(d->isolate, isolate);
v8::HandleScope handle_scope(d->isolate);
DenoIsolate* d = static_cast<DenoIsolate*>(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<v8::Value> 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<v8::Value>& args) {
CHECK_GE(args.Length(), 1);
CHECK_LE(args.Length(), 2);
auto* isolate = args.GetIsolate();
Deno* d = static_cast<Deno*>(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<v8::Value>& args) {
stream << cstr << std::endl;
}
static v8::Local<v8::Uint8Array> ImportBuf(Deno* d, deno_buf buf) {
v8::Local<v8::Uint8Array> 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<v8::Uint8Array> 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<void*>(buf.alloc_ptr), buf.alloc_len,
d->isolate_, reinterpret_cast<void*>(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<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
Deno* d = reinterpret_cast<Deno*>(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<v8::Value>& args) {
CHECK(v->IsFunction());
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(v);
d->recv.Reset(isolate, func);
d->recv_.Reset(isolate, func);
}
void Send(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
Deno* d = static_cast<Deno*>(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<v8::Value> control_v = args[0];
CHECK(control_v->IsArrayBufferView());
@ -294,16 +308,16 @@ void Send(const v8::FunctionCallbackInfo<v8::Value>& 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<v8::Value>& args) {
// Sets the global error handler.
void SetGlobalErrorHandler(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
Deno* d = reinterpret_cast<Deno*>(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<v8::Value>& args) {
CHECK(v->IsFunction());
v8::Local<v8::Function> func = v8::Local<v8::Function>::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<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
Deno* d = reinterpret_cast<Deno*>(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<v8::Value>& args) {
CHECK(v->IsFunction());
v8::Local<v8::Function> func = v8::Local<v8::Function>::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<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
Deno* d = reinterpret_cast<Deno*>(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<v8::Value>& args) {
CHECK(v->IsFunction());
v8::Local<v8::Function> func = v8::Local<v8::Function>::Cast(v);
d->promise_error_examiner.Reset(isolate, func);
d->promise_error_examiner_.Reset(isolate, func);
}
bool ExecuteV8StringSource(v8::Local<v8::Context> context,
@ -502,145 +516,16 @@ void InitializeContext(v8::Isolate* isolate, v8::Local<v8::Context> 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<v8::Value> 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<v8::Value> 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"

View file

@ -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.

View file

@ -6,32 +6,67 @@
#include <string>
#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<v8::Value>* currentArgs;
std::string last_exception;
v8::Persistent<v8::Function> recv;
v8::Persistent<v8::Function> global_error_handler;
v8::Persistent<v8::Function> promise_reject_handler;
v8::Persistent<v8::Function> promise_error_examiner;
v8::StartupData snapshot;
v8::Persistent<v8::ArrayBuffer> global_import_buf;
void* global_import_buf_ptr;
int32_t pending_promise_events;
v8::Persistent<v8::Context> context;
std::map<int32_t, v8::Persistent<v8::Value>> 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<const char*>(snapshot.data_ptr);
snapshot_.raw_size = static_cast<int>(snapshot.data_len);
}
}
void AddIsolate(v8::Isolate* isolate);
v8::Isolate* isolate_;
// Put v8::Isolate::CreateParams here..
const v8::FunctionCallbackInfo<v8::Value>* 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<v8::Context> context_;
std::map<int32_t, v8::Persistent<v8::Value>> async_data_map_;
std::string last_exception_;
v8::Persistent<v8::Function> recv_;
v8::Persistent<v8::Function> global_error_handler_;
v8::Persistent<v8::Function> promise_reject_handler_;
v8::Persistent<v8::Function> promise_error_examiner_;
v8::StartupData snapshot_;
v8::Persistent<v8::ArrayBuffer> 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<v8::Context> 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<v8::Context> context,
v8::Local<v8::Value> exception);
void DeserializeInternalFields(v8::Local<v8::Object> holder, int index,
v8::StartupData payload, void* data);
v8::Local<v8::Uint8Array> ImportBuf(DenoIsolate* d, deno_buf buf);
void DeleteDataRef(DenoIsolate* d, int32_t req_id);
bool Execute(v8::Local<v8::Context> 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_

View file

@ -1,67 +0,0 @@
// Copyright 2018 the Deno authors. All rights reserved. MIT license.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#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<InternalFieldData*> deserialized_data;
void DeserializeInternalFields(v8::Local<v8::Object> 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<const char*>(snapshot.data_ptr);
d->snapshot.raw_size = static_cast<int>(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::ObjectTemplate>(),
v8::MaybeLocal<v8::Value>(),
v8::DeserializeInternalFieldsCallback(
deno::DeserializeInternalFields, nullptr));
d->context.Reset(d->isolate, context);
}
return d;
}
}