From df4aeb82744c4e8e56ac830b73166cb562050b1c Mon Sep 17 00:00:00 2001 From: Alex Hultman Date: Wed, 15 Jan 2020 18:19:47 +0100 Subject: [PATCH] Introduce CallJS and corresponding PERFORM_LIKE_GARBAGE flag --- src/AppWrapper.h | 13 +++++++------ src/HttpRequestWrapper.h | 1 + src/HttpResponseWrapper.h | 7 ++++--- src/Utilities.h | 17 +++++++++++++++++ src/WebSocketWrapper.h | 1 + src/addon.cpp | 2 ++ src/uws.js | 5 ----- 7 files changed, 32 insertions(+), 14 deletions(-) diff --git a/src/AppWrapper.h b/src/AppWrapper.h index 3bd999f..f108f5e 100644 --- a/src/AppWrapper.h +++ b/src/AppWrapper.h @@ -88,7 +88,7 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { Local openLf = Local::New(isolate, openPf); if (!openLf->IsUndefined()) { Local argv[] = {wsObject, reqObject}; - openLf->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 2, argv).IsEmpty(); + CallJS(isolate, openLf, 2, argv); } }; @@ -103,7 +103,8 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { Local argv[3] = {Local::New(isolate, *(perSocketData->socketPf)), messageArrayBuffer, Boolean::New(isolate, opCode == uWS::OpCode::BINARY)}; - Local::New(isolate, messagePf)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 3, argv).IsEmpty(); + + CallJS(isolate, Local::New(isolate, messagePf), 3, argv); /* Important: we clear the ArrayBuffer to make sure it is not invalidly used after return */ messageArrayBuffer->Neuter(); @@ -118,7 +119,7 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { PerSocketData *perSocketData = (PerSocketData *) ws->getUserData(); Local argv[1] = {Local::New(isolate, *(perSocketData->socketPf)) }; - Local::New(isolate, drainPf)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 1, argv).IsEmpty(); + CallJS(isolate, Local::New(isolate, drainPf), 1, argv); }; } @@ -146,7 +147,7 @@ void uWS_App_ws(const FunctionCallbackInfo &args) { Local closeLf = Local::New(isolate, closePf); if (!closeLf->IsUndefined()) { Local argv[3] = {wsObject, Integer::New(isolate, code), messageArrayBuffer}; - closeLf->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 3, argv).IsEmpty(); + CallJS(isolate, closeLf, 3, argv); } delete perSocketData->socketPf; @@ -186,7 +187,7 @@ void uWS_App_get(F f, const FunctionCallbackInfo &args) { reqObject->SetAlignedPointerInInternalField(0, req); Local argv[] = {resObject, reqObject}; - cb.Get(isolate)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 2, argv).IsEmpty(); + CallJS(isolate, cb.Get(isolate), 2, argv); /* Properly invalidate req */ reqObject->SetAlignedPointerInInternalField(0, nullptr); @@ -215,7 +216,7 @@ void uWS_App_listen(const FunctionCallbackInfo &args) { auto cb = [&args, isolate](auto *token) { /* Return a false boolean if listen failed */ Local argv[] = {token ? Local::Cast(External::New(isolate, token)) : Local::Cast(Boolean::New(isolate, false))}; - Local::Cast(args[args.Length() - 1])->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 1, argv).IsEmpty(); + CallJS(isolate, Local::Cast(args[args.Length() - 1]), 1, argv); }; /* Host is first, if present */ diff --git a/src/HttpRequestWrapper.h b/src/HttpRequestWrapper.h index 2f60d91..5981aa0 100644 --- a/src/HttpRequestWrapper.h +++ b/src/HttpRequestWrapper.h @@ -28,6 +28,7 @@ struct HttpRequestWrapper { for (auto p : *req) { Local argv[] = {String::NewFromUtf8(isolate, p.first.data(), NewStringType::kNormal, p.first.length()).ToLocalChecked(), String::NewFromUtf8(isolate, p.second.data(), NewStringType::kNormal, p.second.length()).ToLocalChecked()}; + /* This one is also called from JS so no need for CallJS */ cb->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 2, argv).IsEmpty(); } } diff --git a/src/HttpResponseWrapper.h b/src/HttpResponseWrapper.h index fc19cc7..689b28b 100644 --- a/src/HttpResponseWrapper.h +++ b/src/HttpResponseWrapper.h @@ -47,7 +47,7 @@ struct HttpResponseWrapper { Local dataArrayBuffer = ArrayBuffer::New(isolate, (void *) data.data(), data.length()); Local argv[] = {dataArrayBuffer, Boolean::New(isolate, last)}; - Local::New(isolate, p)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 2, argv).IsEmpty(); + CallJS(isolate, Local::New(isolate, p), 2, argv); dataArrayBuffer->Neuter(); }); @@ -74,7 +74,7 @@ struct HttpResponseWrapper { /* Mark this resObject invalid */ Local::New(isolate, resObject)->SetAlignedPointerInInternalField(0, nullptr); - Local::New(isolate, p)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 0, nullptr).IsEmpty(); + CallJS(isolate, Local::New(isolate, p), 0, nullptr); }); args.GetReturnValue().Set(args.Holder()); @@ -119,7 +119,7 @@ struct HttpResponseWrapper { Local argv[] = {Integer::NewFromUnsigned(isolate, offset)}; /* We should check if this is really here! */ - MaybeLocal maybeBoolean = Local::New(isolate, p)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 1, argv); + MaybeLocal maybeBoolean = CallJS(isolate, Local::New(isolate, p), 1, argv); if (maybeBoolean.IsEmpty()) { std::cerr << "ERROR! onWritable must return a boolean value according to documentation!" << std::endl; exit(-1); @@ -240,6 +240,7 @@ struct HttpResponseWrapper { if (res) { res->cork([cb = Local::Cast(args[0]), isolate]() { + /* This one is called from JS so we don't need CallJS */ cb->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 0, nullptr).IsEmpty(); }); diff --git a/src/Utilities.h b/src/Utilities.h index 256591a..a81b46d 100644 --- a/src/Utilities.h +++ b/src/Utilities.h @@ -4,6 +4,23 @@ #include using namespace v8; +/* Unfortunately we have to perform like garbage to be friends with Node.js */ +#define PERFORM_LIKE_GARBAGE + +/* Unfortunately we have to depend on Node.js garbage */ +#include + +/* This is a very hot function ruined by illiteracy */ +MaybeLocal CallJS(Isolate *isolate, Local f, int argc, Local *argv) { + #ifdef PERFORM_LIKE_GARBAGE + /* Node.js is built by incompetent people who should never have touched a computer in the first place */ + return node::MakeCallback(isolate, isolate->GetCurrentContext()->Global(), f, argc, argv, {0, 0}); + #else + /* Google LLC don't hire incompetent people to work on their stuff */ + return f->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), argc, argv); + #endif +} + struct PerContextData { Isolate *isolate; UniquePersistent reqTemplate; diff --git a/src/WebSocketWrapper.h b/src/WebSocketWrapper.h index 6490e02..6035826 100644 --- a/src/WebSocketWrapper.h +++ b/src/WebSocketWrapper.h @@ -157,6 +157,7 @@ struct WebSocketWrapper { if (ws) { ws->cork([cb = Local::Cast(args[0]), isolate]() { + /* No need for CallJS here */ cb->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 0, nullptr).IsEmpty(); }); diff --git a/src/addon.cpp b/src/addon.cpp index 1ca8717..22a7218 100644 --- a/src/addon.cpp +++ b/src/addon.cpp @@ -82,9 +82,11 @@ void Main(Local exports) { /* We pass isolate everywhere */ Isolate *isolate = exports->GetIsolate(); +#ifndef PERFORM_LIKE_GARBAGE /* We want this so that we can redefine process.nextTick to using the V8 native microtask queue */ /* Settings this crashes Node.js while debugging with breakpoints */ isolate->SetMicrotasksPolicy(MicrotasksPolicy::kAuto); +#endif /* Init the template objects, SSL and non-SSL, store it in per context data */ PerContextData *perContextData = new PerContextData; diff --git a/src/uws.js b/src/uws.js index 2ce00ea..6e34043 100644 --- a/src/uws.js +++ b/src/uws.js @@ -18,11 +18,6 @@ module.exports = (() => { try { const uWS = require('./uws_' + process.platform + '_' + process.arch + '_' + process.versions.modules + '.node'); - process.nextTick = (f, ...args) => { - Promise.resolve().then(() => { - f(...args); - }); - }; process.on('exit', uWS.free); return uWS; } catch (e) {