From 503cf160adb09930207728ef1bcfa210907db020 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Wed, 14 Aug 2024 23:21:59 +0200 Subject: [PATCH] src: refactor http parser binding initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use the per-isolate template to build constants and functions which is faster - Use Array::New() with prebuilt vectors which is faster - Register external references so the binding can be included in the snapshot PR-URL: https://github.com/nodejs/node/pull/54276 Reviewed-By: Michaƫl Zasso Reviewed-By: Matteo Collina Reviewed-By: Paolo Insogna Reviewed-By: Anna Henningsen Reviewed-By: Robert Nagy Reviewed-By: James M Snell Reviewed-By: Ethan Arrowood --- src/node_binding.h | 1 + src/node_external_reference.h | 1 + src/node_http_parser.cc | 219 +++++++++++++++++++--------------- 3 files changed, 128 insertions(+), 93 deletions(-) diff --git a/src/node_binding.h b/src/node_binding.h index 094d14cb2ee6ac..eb1364cb01a2be 100644 --- a/src/node_binding.h +++ b/src/node_binding.h @@ -44,6 +44,7 @@ static_assert(static_cast(NM_F_LINKED) == V(encoding_binding) \ V(fs) \ V(fs_dir) \ + V(http_parser) \ V(messaging) \ V(mksnapshot) \ V(modules) \ diff --git a/src/node_external_reference.h b/src/node_external_reference.h index b59a3a9e9c957a..626c3da5b1b866 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -141,6 +141,7 @@ class ExternalReferenceRegistry { V(fs_event_wrap) \ V(handle_wrap) \ V(heap_utils) \ + V(http_parser) \ V(internal_only_v8) \ V(messaging) \ V(mksnapshot) \ diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 66e0a7e5428006..dfb278151c9566 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -25,10 +25,11 @@ #include "async_wrap-inl.h" #include "env-inl.h" +#include "llhttp.h" #include "memory_tracker-inl.h" +#include "node_external_reference.h" #include "stream_base-inl.h" #include "v8.h" -#include "llhttp.h" #include // free() #include // strdup(), strchr() @@ -47,7 +48,7 @@ namespace node { -namespace { // NOLINT(build/namespaces) +namespace http_parser { // NOLINT(build/namespaces) using v8::Array; using v8::Boolean; @@ -65,6 +66,7 @@ using v8::Local; using v8::MaybeLocal; using v8::Number; using v8::Object; +using v8::ObjectTemplate; using v8::String; using v8::Uint32; using v8::Undefined; @@ -1243,97 +1245,59 @@ const llhttp_settings_t Parser::settings = { nullptr, }; -void InitializeHttpParser(Local target, - Local unused, - Local context, - void* priv) { - Realm* realm = Realm::GetCurrent(context); - Environment* env = realm->env(); - Isolate* isolate = env->isolate(); - BindingData* const binding_data = realm->AddBindingData(target); - if (binding_data == nullptr) return; +void CreatePerIsolateProperties(IsolateData* isolate_data, + Local target) { + Isolate* isolate = isolate_data->isolate(); Local t = NewFunctionTemplate(isolate, Parser::New); t->InstanceTemplate()->SetInternalFieldCount(Parser::kInternalFieldCount); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "REQUEST"), - Integer::New(env->isolate(), HTTP_REQUEST)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "RESPONSE"), - Integer::New(env->isolate(), HTTP_RESPONSE)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageBegin"), - Integer::NewFromUnsigned(env->isolate(), kOnMessageBegin)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeaders"), - Integer::NewFromUnsigned(env->isolate(), kOnHeaders)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnHeadersComplete"), - Integer::NewFromUnsigned(env->isolate(), kOnHeadersComplete)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnBody"), - Integer::NewFromUnsigned(env->isolate(), kOnBody)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnMessageComplete"), - Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"), - Integer::NewFromUnsigned(env->isolate(), kOnExecute)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnTimeout"), - Integer::NewFromUnsigned(env->isolate(), kOnTimeout)); - - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientNone"), - Integer::NewFromUnsigned(env->isolate(), kLenientNone)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientHeaders"), - Integer::NewFromUnsigned(env->isolate(), kLenientHeaders)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientChunkedLength"), - Integer::NewFromUnsigned(env->isolate(), kLenientChunkedLength)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientKeepAlive"), - Integer::NewFromUnsigned(env->isolate(), kLenientKeepAlive)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientTransferEncoding"), - Integer::NewFromUnsigned(env->isolate(), kLenientTransferEncoding)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientVersion"), - Integer::NewFromUnsigned(env->isolate(), kLenientVersion)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientDataAfterClose"), - Integer::NewFromUnsigned(env->isolate(), kLenientDataAfterClose)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientOptionalLFAfterCR"), - Integer::NewFromUnsigned(env->isolate(), kLenientOptionalLFAfterCR)); - t->Set( - FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientOptionalCRLFAfterChunk"), - Integer::NewFromUnsigned(env->isolate(), kLenientOptionalCRLFAfterChunk)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientOptionalCRBeforeLF"), - Integer::NewFromUnsigned(env->isolate(), kLenientOptionalCRBeforeLF)); - t->Set( - FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientSpacesAfterChunkSize"), - Integer::NewFromUnsigned(env->isolate(), kLenientSpacesAfterChunkSize)); - - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kLenientAll"), - Integer::NewFromUnsigned(env->isolate(), kLenientAll)); - - Local methods = Array::New(env->isolate()); - Local all_methods = Array::New(env->isolate()); - size_t method_index = -1; - size_t all_method_index = -1; -#define V(num, name, string) \ - methods \ - ->Set(env->context(), \ - ++method_index, \ - FIXED_ONE_BYTE_STRING(env->isolate(), #string)) \ - .Check(); - HTTP_METHOD_MAP(V) -#undef V -#define V(num, name, string) \ - all_methods \ - ->Set(env->context(), \ - ++all_method_index, \ - FIXED_ONE_BYTE_STRING(env->isolate(), #string)) \ - .Check(); - HTTP_ALL_METHOD_MAP(V) -#undef V - - target->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "methods"), - methods).Check(); - target - ->Set(env->context(), - FIXED_ONE_BYTE_STRING(env->isolate(), "allMethods"), - all_methods) - .Check(); - - t->Inherit(AsyncWrap::GetConstructorTemplate(env)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "REQUEST"), + Integer::New(isolate, HTTP_REQUEST)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "RESPONSE"), + Integer::New(isolate, HTTP_RESPONSE)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kOnMessageBegin"), + Integer::NewFromUnsigned(isolate, kOnMessageBegin)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kOnHeaders"), + Integer::NewFromUnsigned(isolate, kOnHeaders)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kOnHeadersComplete"), + Integer::NewFromUnsigned(isolate, kOnHeadersComplete)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kOnBody"), + Integer::NewFromUnsigned(isolate, kOnBody)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kOnMessageComplete"), + Integer::NewFromUnsigned(isolate, kOnMessageComplete)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kOnExecute"), + Integer::NewFromUnsigned(isolate, kOnExecute)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kOnTimeout"), + Integer::NewFromUnsigned(isolate, kOnTimeout)); + + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientNone"), + Integer::NewFromUnsigned(isolate, kLenientNone)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientHeaders"), + Integer::NewFromUnsigned(isolate, kLenientHeaders)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientChunkedLength"), + Integer::NewFromUnsigned(isolate, kLenientChunkedLength)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientKeepAlive"), + Integer::NewFromUnsigned(isolate, kLenientKeepAlive)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientTransferEncoding"), + Integer::NewFromUnsigned(isolate, kLenientTransferEncoding)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientVersion"), + Integer::NewFromUnsigned(isolate, kLenientVersion)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientDataAfterClose"), + Integer::NewFromUnsigned(isolate, kLenientDataAfterClose)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientOptionalLFAfterCR"), + Integer::NewFromUnsigned(isolate, kLenientOptionalLFAfterCR)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientOptionalCRLFAfterChunk"), + Integer::NewFromUnsigned(isolate, kLenientOptionalCRLFAfterChunk)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientOptionalCRBeforeLF"), + Integer::NewFromUnsigned(isolate, kLenientOptionalCRBeforeLF)); + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientSpacesAfterChunkSize"), + Integer::NewFromUnsigned(isolate, kLenientSpacesAfterChunkSize)); + + t->Set(FIXED_ONE_BYTE_STRING(isolate, "kLenientAll"), + Integer::NewFromUnsigned(isolate, kLenientAll)); + + t->Inherit(AsyncWrap::GetConstructorTemplate(isolate_data)); SetProtoMethod(isolate, t, "close", Parser::Close); SetProtoMethod(isolate, t, "free", Parser::Free); SetProtoMethod(isolate, t, "remove", Parser::Remove); @@ -1348,7 +1312,7 @@ void InitializeHttpParser(Local target, SetProtoMethod(isolate, t, "duration", Parser::Duration); SetProtoMethod(isolate, t, "headersCompleted", Parser::HeadersCompleted); - SetConstructorFunction(context, target, "HTTPParser", t); + SetConstructorFunction(isolate, target, "HTTPParser", t); Local c = NewFunctionTemplate(isolate, ConnectionsList::New); @@ -1358,10 +1322,79 @@ void InitializeHttpParser(Local target, SetProtoMethod(isolate, c, "idle", ConnectionsList::Idle); SetProtoMethod(isolate, c, "active", ConnectionsList::Active); SetProtoMethod(isolate, c, "expired", ConnectionsList::Expired); - SetConstructorFunction(context, target, "ConnectionsList", c); + SetConstructorFunction(isolate, target, "ConnectionsList", c); +} + +void CreatePerContextProperties(Local target, + Local unused, + Local context, + void* priv) { + Realm* realm = Realm::GetCurrent(context); + Environment* env = realm->env(); + Isolate* isolate = env->isolate(); + BindingData* const binding_data = realm->AddBindingData(target); + if (binding_data == nullptr) return; + + std::vector> methods_val; + std::vector> all_methods_val; + +#define V(num, name, string) \ + methods_val.push_back(FIXED_ONE_BYTE_STRING(isolate, #string)); + HTTP_METHOD_MAP(V) +#undef V +#define V(num, name, string) \ + all_methods_val.push_back(FIXED_ONE_BYTE_STRING(isolate, #string)); + HTTP_ALL_METHOD_MAP(V) +#undef V + + Local methods = + Array::New(isolate, methods_val.data(), methods_val.size()); + Local all_methods = + Array::New(isolate, all_methods_val.data(), all_methods_val.size()); + if (!target + ->Set(env->context(), + FIXED_ONE_BYTE_STRING(isolate, "methods"), + methods) + .IsJust()) { + return; + } + if (target + ->Set(env->context(), + FIXED_ONE_BYTE_STRING(isolate, "allMethods"), + all_methods) + .IsJust()) { + return; + } +} + +void RegisterExternalReferences(ExternalReferenceRegistry* registry) { + registry->Register(Parser::New); + registry->Register(Parser::Close); + registry->Register(Parser::Free); + registry->Register(Parser::Remove); + registry->Register(Parser::Execute); + registry->Register(Parser::Finish); + registry->Register(Parser::Initialize); + registry->Register(Parser::Pause); + registry->Register(Parser::Pause); + registry->Register(Parser::Consume); + registry->Register(Parser::Unconsume); + registry->Register(Parser::GetCurrentBuffer); + registry->Register(Parser::Duration); + registry->Register(Parser::HeadersCompleted); + registry->Register(ConnectionsList::New); + registry->Register(ConnectionsList::All); + registry->Register(ConnectionsList::Idle); + registry->Register(ConnectionsList::Active); + registry->Register(ConnectionsList::Expired); } -} // anonymous namespace +} // namespace http_parser } // namespace node -NODE_BINDING_CONTEXT_AWARE_INTERNAL(http_parser, node::InitializeHttpParser) +NODE_BINDING_CONTEXT_AWARE_INTERNAL( + http_parser, node::http_parser::CreatePerContextProperties) +NODE_BINDING_PER_ISOLATE_INIT(http_parser, + node::http_parser::CreatePerIsolateProperties) +NODE_BINDING_EXTERNAL_REFERENCE(http_parser, + node::http_parser::RegisterExternalReferences)