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:
parent
fd68f85ce8
commit
6afe94b3c8
6 changed files with 330 additions and 297 deletions
2
BUILD.gn
2
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",
|
||||
|
|
162
libdeno/api.cc
Normal file
162
libdeno/api.cc
Normal 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();
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue