Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promises patch v8 #2

Open
wants to merge 3 commits into
base: promises
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion deps/v8/include/v8.h
Original file line number Diff line number Diff line change
Expand Up @@ -5260,6 +5260,8 @@ class V8_EXPORT PersistentHandleVisitor { // NOLINT
*/
class V8_EXPORT Isolate {
public:
class MicrotaskQueue;

/**
* Initial configuration parameters for a new Isolate.
*/
Expand All @@ -5271,7 +5273,8 @@ class V8_EXPORT Isolate {
counter_lookup_callback(NULL),
create_histogram_callback(NULL),
add_histogram_sample_callback(NULL),
array_buffer_allocator(NULL) {}
array_buffer_allocator(NULL),
microtask_queue(NULL) {}

/**
* The optional entry_hook allows the host application to provide the
Expand Down Expand Up @@ -5319,6 +5322,11 @@ class V8_EXPORT Isolate {
* store of ArrayBuffers.
*/
ArrayBuffer::Allocator* array_buffer_allocator;

/**
* The MicrotaskQueue implementation to use.
*/
MicrotaskQueue* microtask_queue;
};


Expand Down Expand Up @@ -5382,6 +5390,18 @@ class V8_EXPORT Isolate {
const AllowJavascriptExecutionScope&);
};

/**
*
*
*/
class V8_EXPORT MicrotaskQueue {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should explain that using Isolate::CreateParams is necessary, in the comments above. Similar to how every other class that makes use of Isolate::CreateParams.

public:
virtual ~MicrotaskQueue() {};
virtual void Enqueue(Local<Function>) = 0;
virtual void Enqueue(MicrotaskCallback, void*) = 0;
virtual void Run() = 0;
};

/**
* Do not run microtasks while this scope is active, even if microtasks are
* automatically executed otherwise.
Expand Down
17 changes: 9 additions & 8 deletions deps/v8/src/api.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7153,6 +7153,11 @@ Isolate* Isolate::New(const Isolate::CreateParams& params) {
Isolate* v8_isolate = reinterpret_cast<Isolate*>(isolate);
CHECK(params.array_buffer_allocator != NULL);
isolate->set_array_buffer_allocator(params.array_buffer_allocator);
if (params.microtask_queue != NULL) {
isolate->set_microtask_queue(params.microtask_queue);
} else {
isolate->set_microtask_queue(isolate->CreateDefaultMicrotaskQueue());
}
if (params.snapshot_blob != NULL) {
isolate->set_snapshot_blob(params.snapshot_blob);
} else {
Expand Down Expand Up @@ -7395,19 +7400,15 @@ void Isolate::RunMicrotasks() {

void Isolate::EnqueueMicrotask(Local<Function> microtask) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->EnqueueMicrotask(Utils::OpenHandle(*microtask));
isolate->ExtEnqueueMicrotask(microtask);

//Utils::OpenHandle(*microtask));
}


void Isolate::EnqueueMicrotask(MicrotaskCallback microtask, void* data) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
i::HandleScope scope(isolate);
i::Handle<i::CallHandlerInfo> callback_info =
i::Handle<i::CallHandlerInfo>::cast(
isolate->factory()->NewStruct(i::CALL_HANDLER_INFO_TYPE));
SET_FIELD_WRAPPED(callback_info, set_callback, microtask);
SET_FIELD_WRAPPED(callback_info, set_data, data);
isolate->EnqueueMicrotask(callback_info);
isolate->ExtEnqueueMicrotask(microtask, data);
}


Expand Down
91 changes: 68 additions & 23 deletions deps/v8/src/isolate.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2642,55 +2642,100 @@ void Isolate::ReportPromiseReject(Handle<JSObject> promise,
}


void Isolate::ExtEnqueueMicrotask(v8::Local<v8::Function> microtask) {
EnqueueMicrotask(Utils::OpenHandle(*microtask));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not leave this DCHECK in place and drop the abort() call?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point! Will fix.

microtask_queue()->Enqueue(microtask);
}


void Isolate::ExtEnqueueMicrotask(MicrotaskCallback microtask, void* data) {
microtask_queue()->Enqueue(microtask, data);
}


void Isolate::EnqueueMicrotask(Handle<Object> microtask) {
DCHECK(microtask->IsJSFunction() || microtask->IsCallHandlerInfo());
Handle<FixedArray> queue(heap()->microtask_queue(), this);
int num_tasks = pending_microtask_count();
if (microtask->IsJSFunction()) {
microtask_queue()->Enqueue(
Utils::ToLocal(Handle<JSObject>::cast(microtask)).As<Function>());
} else {
// panic?
abort();
}
}


#define SET_FIELD_WRAPPED(obj, setter, cdata) do { \
Handle<Object> foreign = FromCData(obj->GetIsolate(), cdata); \
(obj)->setter(*foreign); \
} while (false)


void Isolate::DefaultMicrotaskQueue::Enqueue(v8::MicrotaskCallback microtask, void* data) {
HandleScope scope(isolate());
Handle<CallHandlerInfo> callback_info =
Handle<CallHandlerInfo>::cast(
isolate()->factory()->NewStruct(CALL_HANDLER_INFO_TYPE));
SET_FIELD_WRAPPED(callback_info, set_callback, microtask);
SET_FIELD_WRAPPED(callback_info, set_data, data);
isolate()->EnqueueMicrotask(callback_info);
}


void Isolate::DefaultMicrotaskQueue::Enqueue(Local<v8::Function> microtask) {
Handle<Object> internal_microtask = Utils::OpenHandle(*microtask);
DCHECK(internal_microtask->IsJSFunction() || internal_microtask->IsCallHandlerInfo());
Handle<FixedArray> queue(isolate()->heap()->microtask_queue(), isolate());
int num_tasks = isolate()->pending_microtask_count();
DCHECK(num_tasks <= queue->length());
if (num_tasks == 0) {
queue = factory()->NewFixedArray(8);
heap()->set_microtask_queue(*queue);
queue = isolate()->factory()->NewFixedArray(8);
isolate()->heap()->set_microtask_queue(*queue);
} else if (num_tasks == queue->length()) {
queue = factory()->CopyFixedArrayAndGrow(queue, num_tasks);
heap()->set_microtask_queue(*queue);
queue = isolate()->factory()->CopyFixedArrayAndGrow(queue, num_tasks);
isolate()->heap()->set_microtask_queue(*queue);
}
DCHECK(queue->get(num_tasks)->IsUndefined());
queue->set(num_tasks, *microtask);
set_pending_microtask_count(num_tasks + 1);
queue->set(num_tasks, *internal_microtask);
isolate()->set_pending_microtask_count(num_tasks + 1);
}


void Isolate::RunMicrotasks() {
microtask_queue()->Run();
}


void Isolate::DefaultMicrotaskQueue::Run() {
// Increase call depth to prevent recursive callbacks.
v8::Isolate::SuppressMicrotaskExecutionScope suppress(
reinterpret_cast<v8::Isolate*>(this));
reinterpret_cast<v8::Isolate*>(isolate()));

while (pending_microtask_count() > 0) {
HandleScope scope(this);
int num_tasks = pending_microtask_count();
Handle<FixedArray> queue(heap()->microtask_queue(), this);
while (isolate()->pending_microtask_count() > 0) {
HandleScope scope(isolate());
int num_tasks = isolate()->pending_microtask_count();
Handle<FixedArray> queue(isolate()->heap()->microtask_queue(), isolate());
DCHECK(num_tasks <= queue->length());
set_pending_microtask_count(0);
heap()->set_microtask_queue(heap()->empty_fixed_array());
isolate()->set_pending_microtask_count(0);
isolate()->heap()->set_microtask_queue(isolate()->heap()->empty_fixed_array());

for (int i = 0; i < num_tasks; i++) {
HandleScope scope(this);
Handle<Object> microtask(queue->get(i), this);
HandleScope scope(isolate());
Handle<Object> microtask(queue->get(i), isolate());
if (microtask->IsJSFunction()) {
Handle<JSFunction> microtask_function =
Handle<JSFunction>::cast(microtask);
SaveContext save(this);
set_context(microtask_function->context()->native_context());
SaveContext save(isolate());
isolate()->set_context(microtask_function->context()->native_context());
MaybeHandle<Object> maybe_exception;
MaybeHandle<Object> result = Execution::TryCall(
this, microtask_function, factory()->undefined_value(), 0, NULL,
isolate(), microtask_function, isolate()->factory()->undefined_value(), 0, NULL,
&maybe_exception);
// If execution is terminating, just bail out.
Handle<Object> exception;
if (result.is_null() && maybe_exception.is_null()) {
// Clear out any remaining callbacks in the queue.
heap()->set_microtask_queue(heap()->empty_fixed_array());
set_pending_microtask_count(0);
isolate()->heap()->set_microtask_queue(isolate()->heap()->empty_fixed_array());
isolate()->set_pending_microtask_count(0);
return;
}
} else {
Expand Down
31 changes: 31 additions & 0 deletions deps/v8/src/isolate.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,23 @@ class Isolate {
};


class DefaultMicrotaskQueue : public v8::Isolate::MicrotaskQueue {
public:
virtual ~DefaultMicrotaskQueue() {};

virtual void Enqueue(Local<v8::Function>);
virtual void Enqueue(v8::MicrotaskCallback, void*);
virtual void Run();
Isolate* isolate() const { return isolate_; }
private:
DefaultMicrotaskQueue(Isolate* isolate) : isolate_(isolate) {
};
Isolate* isolate_;
friend class Isolate;
DISALLOW_COPY_AND_ASSIGN(DefaultMicrotaskQueue);
};


enum AddressId {
#define DECLARE_ENUM(CamelName, hacker_name) k##CamelName##Address,
FOR_EACH_ISOLATE_ADDRESS_NAME(DECLARE_ENUM)
Expand Down Expand Up @@ -515,6 +532,10 @@ class Isolate {

void ClearSerializerData();

v8::Isolate::MicrotaskQueue* CreateDefaultMicrotaskQueue() {
return new DefaultMicrotaskQueue(this);
}

// Find the PerThread for this particular (isolate, thread) combination
// If one does not yet exist, return null.
PerIsolateThreadData* FindPerThreadDataForThisThread();
Expand Down Expand Up @@ -1064,6 +1085,8 @@ class Isolate {
v8::PromiseRejectEvent event);

void EnqueueMicrotask(Handle<Object> microtask);
void ExtEnqueueMicrotask(Local<v8::Function> microtask);
void ExtEnqueueMicrotask(v8::MicrotaskCallback, void*);
void RunMicrotasks();

void SetUseCounterCallback(v8::Isolate::UseCounterCallback callback);
Expand Down Expand Up @@ -1091,6 +1114,13 @@ class Isolate {
return array_buffer_allocator_;
}

void set_microtask_queue(v8::Isolate::MicrotaskQueue* queue) {
microtask_queue_ = queue;
};
v8::Isolate::MicrotaskQueue* microtask_queue() const {
return microtask_queue_;
}

FutexWaitListNode* futex_wait_list_node() { return &futex_wait_list_node_; }

void RegisterCancelableTask(Cancelable* task);
Expand Down Expand Up @@ -1335,6 +1365,7 @@ class Isolate {
List<Object*> partial_snapshot_cache_;

v8::ArrayBuffer::Allocator* array_buffer_allocator_;
v8::Isolate::MicrotaskQueue* microtask_queue_;

FutexWaitListNode futex_wait_list_node_;

Expand Down
1 change: 1 addition & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ namespace node {
V(name_string, "name") \
V(need_imm_cb_string, "_needImmediateCallback") \
V(netmask_string, "netmask") \
V(nexttick_string, "nextTick") \
V(nice_string, "nice") \
V(nlink_string, "nlink") \
V(npn_buffer_string, "npnBuffer") \
Expand Down
29 changes: 29 additions & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,31 @@ Local<Value> WinapiErrnoException(Isolate* isolate,
#endif


void MicrotaskQueue::Enqueue(v8::Local<v8::Function> microtask) {
printf("Enqueue fn\n");
HandleScope scope(env_->isolate());
Local<Object> process_object = env_->process_object();
Local<String> nexttick_string = env_->nexttick_string();
Local<Function> nexttick =
process_object->Get(nexttick_string).As<Function>();
if (!nexttick->IsFunction()) {
fprintf(stderr, "process.nextTick assigned to non-function\n");
ABORT();
}
Local<Value> args[] = { microtask };
nexttick->Call(process_object, ARRAY_SIZE(args), args);
}


void MicrotaskQueue::Enqueue(v8::MicrotaskCallback, void*) {
printf("Enqueue cfn\n");
}


void MicrotaskQueue::Run() {
}


void* ArrayBufferAllocator::Allocate(size_t size) {
if (env_ == nullptr || !env_->array_buffer_allocator_info()->no_zero_fill())
return calloc(size, 1);
Expand Down Expand Up @@ -4108,6 +4133,9 @@ static void StartNodeInstance(void* arg) {
Isolate::CreateParams params;
ArrayBufferAllocator* array_buffer_allocator = new ArrayBufferAllocator();
params.array_buffer_allocator = array_buffer_allocator;

MicrotaskQueue* microtask_queue = new MicrotaskQueue();
params.microtask_queue = microtask_queue;
#ifdef NODE_ENABLE_VTUNE_PROFILING
params.code_event_handler = vTune::GetVtuneCodeEventHandler();
#endif
Expand All @@ -4128,6 +4156,7 @@ static void StartNodeInstance(void* arg) {
Local<Context> context = Context::New(isolate);
Environment* env = CreateEnvironment(isolate, context, instance_data);
array_buffer_allocator->set_env(env);
microtask_queue->set_env(env);
Context::Scope context_scope(context);

isolate->SetAbortOnUncaughtExceptionCallback(
Expand Down
14 changes: 14 additions & 0 deletions src/node_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,20 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
Environment* env_;
};

class MicrotaskQueue : public v8::Isolate::MicrotaskQueue {
public:
MicrotaskQueue() : env_(nullptr) { }
virtual ~MicrotaskQueue() { }
inline void set_env(Environment* env) { env_ = env; }

virtual void Enqueue(v8::Local<v8::Function>);
virtual void Enqueue(v8::MicrotaskCallback, void*);
virtual void Run();

private:
Environment* env_;
};

enum NodeInstanceType { MAIN, WORKER };

class NodeInstanceData {
Expand Down