Introduce CallJS and corresponding PERFORM_LIKE_GARBAGE flag

This commit is contained in:
Alex Hultman 2020-01-15 18:19:47 +01:00
parent 68fde105e6
commit df4aeb8274
7 changed files with 32 additions and 14 deletions

View File

@ -88,7 +88,7 @@ void uWS_App_ws(const FunctionCallbackInfo<Value> &args) {
Local<Function> openLf = Local<Function>::New(isolate, openPf);
if (!openLf->IsUndefined()) {
Local<Value> 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<Value> &args) {
Local<Value> argv[3] = {Local<Object>::New(isolate, *(perSocketData->socketPf)),
messageArrayBuffer,
Boolean::New(isolate, opCode == uWS::OpCode::BINARY)};
Local<Function>::New(isolate, messagePf)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 3, argv).IsEmpty();
CallJS(isolate, Local<Function>::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<Value> &args) {
PerSocketData *perSocketData = (PerSocketData *) ws->getUserData();
Local<Value> argv[1] = {Local<Object>::New(isolate, *(perSocketData->socketPf))
};
Local<Function>::New(isolate, drainPf)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 1, argv).IsEmpty();
CallJS(isolate, Local<Function>::New(isolate, drainPf), 1, argv);
};
}
@ -146,7 +147,7 @@ void uWS_App_ws(const FunctionCallbackInfo<Value> &args) {
Local<Function> closeLf = Local<Function>::New(isolate, closePf);
if (!closeLf->IsUndefined()) {
Local<Value> 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<Value> &args) {
reqObject->SetAlignedPointerInInternalField(0, req);
Local<Value> 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<Value> &args) {
auto cb = [&args, isolate](auto *token) {
/* Return a false boolean if listen failed */
Local<Value> argv[] = {token ? Local<Value>::Cast(External::New(isolate, token)) : Local<Value>::Cast(Boolean::New(isolate, false))};
Local<Function>::Cast(args[args.Length() - 1])->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 1, argv).IsEmpty();
CallJS(isolate, Local<Function>::Cast(args[args.Length() - 1]), 1, argv);
};
/* Host is first, if present */

View File

@ -28,6 +28,7 @@ struct HttpRequestWrapper {
for (auto p : *req) {
Local<Value> 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();
}
}

View File

@ -47,7 +47,7 @@ struct HttpResponseWrapper {
Local<ArrayBuffer> dataArrayBuffer = ArrayBuffer::New(isolate, (void *) data.data(), data.length());
Local<Value> argv[] = {dataArrayBuffer, Boolean::New(isolate, last)};
Local<Function>::New(isolate, p)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 2, argv).IsEmpty();
CallJS(isolate, Local<Function>::New(isolate, p), 2, argv);
dataArrayBuffer->Neuter();
});
@ -74,7 +74,7 @@ struct HttpResponseWrapper {
/* Mark this resObject invalid */
Local<Object>::New(isolate, resObject)->SetAlignedPointerInInternalField(0, nullptr);
Local<Function>::New(isolate, p)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 0, nullptr).IsEmpty();
CallJS(isolate, Local<Function>::New(isolate, p), 0, nullptr);
});
args.GetReturnValue().Set(args.Holder());
@ -119,7 +119,7 @@ struct HttpResponseWrapper {
Local<Value> argv[] = {Integer::NewFromUnsigned(isolate, offset)};
/* We should check if this is really here! */
MaybeLocal<Value> maybeBoolean = Local<Function>::New(isolate, p)->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 1, argv);
MaybeLocal<Value> maybeBoolean = CallJS(isolate, Local<Function>::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<Function>::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();
});

View File

@ -4,6 +4,23 @@
#include <v8.h>
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 <node.h>
/* This is a very hot function ruined by illiteracy */
MaybeLocal<Value> CallJS(Isolate *isolate, Local<Function> f, int argc, Local<Value> *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<Object> reqTemplate;

View File

@ -157,6 +157,7 @@ struct WebSocketWrapper {
if (ws) {
ws->cork([cb = Local<Function>::Cast(args[0]), isolate]() {
/* No need for CallJS here */
cb->Call(isolate->GetCurrentContext(), isolate->GetCurrentContext()->Global(), 0, nullptr).IsEmpty();
});

View File

@ -82,9 +82,11 @@ void Main(Local<Object> 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;

View File

@ -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) {