In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-08 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly explains "what is the general logic of C++ layer in nodejs source code analysis". The content in the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what is the general logic of C++ layer in nodejs source code analysis".
We know that nodejs is divided into three layers: js, C++ and c. This paper takes tcp_wrap.cc as an example to analyze some general logic implemented in C++ layer. Nodejs's js and C++ communication principle q.com/s?__biz=MzUyNDE2OTAwNw==&mid=2247484815&idx=1&sn=525d9909c35eabf3c728b303d27061df&chksm=fa303fcfcd47b6d9604298d0996414a5e16c798c1a2dab4e01989bb41ba9c5372ebc00ca0943&token=162783191&lang=zh_CN#rd) have been analyzed before, so the functions derived directly from the tcp module are analyzed (the Initialize function).
Void TCPWrap::Initialize (Local target
Local unused
Local context) {
Environment* env = Environment::GetCurrent (context)
/ *
When new TCP, v8 creates a new C++ object (based on the InstanceTemplate () template) and passes it into the New function
Then execute the New function. The args.This () of the input parameter args of the New function is the C++ object.
, /
/ / create a new function template
Local t = env- > NewFunctionTemplate (New)
/ / set the function name
Local tcpString = FIXED_ONE_BYTE_STRING (env- > isolate (), "TCP")
T-> SetClassName (tcpString)
/ *
The kDataOffset offset of the ObjectTemplateInfo object holds the value of this field
Used to declare the amount of memory requested for additional objects created by ObjectTemplateInfo
, /
T-> InstanceTemplate ()-> SetInternalFieldCount (1)
/ / sets the properties of the object created by the object template. The kPropertyListOffset offset of the ObjectTemplateInfo object holds the following values
T-> InstanceTemplate ()-> Set (FIXED_ONE_BYTE_STRING (env- > isolate (), "reading")
Boolean::New (env- > isolate (), false))
/ / add attributes to the prototype of t
Env- > SetProtoMethod (t, "bind", Bind)
Env- > SetProtoMethod (t, "connect", Connect)
/ / register the function in target
Target- > Set (tcpString, t-> GetFunction ())
Only part of the code is extracted here, because we only focus on the principle, which involves function templates, object templates and function prototypes, respectively. The above code is represented in js as follows:
Function TCP () {
This.reading = false
/ / corresponding SetInternalFieldCount (1)
This.point = null
/ / corresponding env- > NewFunctionTemplate (New)
New ({
Holder: this
This: this
ReturnValue: {}
...
});
}
TCP.prototype.bind = Bind
TCP.prototype.connect = Connect
Through the above definition, complete the export of C++ module function, with the help of nodejs mechanism, we can call the TCP function in the js layer.
Const {TCP, constants: TCPConstants} = process.binding ('tcp_wrap')
Const instance = new TCP (...)
Instance.bind (...)
We first analyze the logic that executes new TCP (), and then analyze the logic of bind, because these two logic involve mechanisms that other C++ modules will also use. Because the function corresponding to TCP is the value corresponding to t-> GetFunction () in the Initialize function. So when new TCP (), v8 first creates a C++ object (the content is defined in the Initialize function, which is defined in the code at the beginning of the article). The callback New function is then executed.
/ / execute when new TCP is executed
Void TCPWrap::New (const FunctionCallbackInfo& args) {
/ / whether to execute as a constructor, that is, new TCP
CHECK (args.IsConstructCall ())
CHECK (args [0]-> IsInt32 ())
Environment* env = Environment::GetCurrent (args)
/ / ignore some unimportant logic
/ *
A C++ object provided by args.This () for v8 (created by a module defined by the Initialize function)
Call the SetAlignedPointerInInternalField (0j this) associated this (new TCPWrap ()) of the C++ object
See HandleWrap
, /
New TCPWrap (env, args.This (), provider)
}
We see that the logic of the New function is simple. Call new TCPWrap directly, where the second input parameter, args.This (), is the object created by the function template defined by the Initialize function. Let's move on to new TCPWrap ().
TCPWrap::TCPWrap (Environment* env
Local object
ProviderType provider)
ConnectionWrap (env, object, provider) {
Int r = uv_tcp_init (env- > event_loop (), & handle_)
}
The constructor has only one line of code, which initializes a structure, so we don't have to pay attention to it, but we need to focus on the logic of the parent class ConnectionWrap.
Template
ConnectionWrap::ConnectionWrap (Environment* env
Local object
ProviderType provider)
: LibuvStreamWrap (env
Object
Reinterpret_cast & handle_)
Provider) {}
We found that ConnectionWrap also has no logic, continue to look at LibuvStreamWrap.
LibuvStreamWrap::LibuvStreamWrap (Environment* env
Local object
Uv_stream_t* stream
AsyncWrap::ProviderType provider)
: HandleWrap (env
Object
Reinterpret_cast (stream)
Provider)
StreamBase (env)
Stream_ (stream) {
}
Continue to do some initialization, we only focus on HandleWrap
HandleWrap::HandleWrap (Environment* env
Local object
Uv_handle_t* handle
AsyncWrap::ProviderType provider)
: AsyncWrap (env, object, provider)
State_ (kInitialized)
Handle_ (handle) {
/ / Mount the subclass object to the data field of handle
Handle_- > data = this
HandleScope scope (env- > isolate ())
/ / Associate object and this objects, which are later used through unwrap
Wrap (object, this)
/ / join the team
Env- > handle_wrap_queue ()-> PushBack (this)
}
The point is, the Wrap function.
Template
Void Wrap (v8::Local object, TypeName* pointer) {
Object- > SetAlignedPointerInInternalField (0, pointer)
}
Void v8::Object::SetAlignedPointerInInternalField (int index, void* value) {
I::Handle obj = Utils::OpenHandle (this)
I::Handle::cast (obj)-> SetEmbedderField (
Index, EncodeAlignedAsSmi (value, location))
}
Void JSObject::SetEmbedderField (int index, Smi* value) {
/ / GetHeaderSize is the size of the fixed layout of the object, and kPointerSize * index is the expanded memory size. Find the corresponding location according to the index.
Int offset = GetHeaderSize () + (kPointerSize * index)
/ / write the memory of the corresponding location, that is, save the corresponding contents to memory
WRITE_FIELD (this, offset, value)
}
After the Wrap function is expanded, all you do is save a value to the memory of the v8 C++ object. So what is the saved value? Let's look at the input parameter Wrap (object, this) of the Wrap function. Object is an object created by a function template, and this is a TCPWrap object. So what the Wrap function does is save a TCPWrap object to an object created by a function template. What's the use of that? Let's continue the analysis. At this point, the implementation of new TCP is finished. Let's take a look at the logic that executes the new TCP (). Bind () function at this time.
Void TCPWrap::Bind (const FunctionCallbackInfo& args) {
TCPWrap* wrap
/ / unpacking processing
ASSIGN_OR_RETURN_UNWRAP & wrap
Args.Holder ()
Args.GetReturnValue () .Set (UV_EBADF))
Node::Utf8Value ip_address (args.GetIsolate (), args [0])
Int port = args [1]-> Int32Value ()
Sockaddr_in addr
Int err = uv_ip4_addr (* ip_address, port, & addr)
If (err = = 0) {
Err = uv_tcp_bind (& wrap- > handle_
Reinterpret_cast & addr)
0)
}
Args.GetReturnValue () Set (err)
}
We only need to relate to the logic of the ASSIGN_OR_RETURN_ UNWRAP macro. Where args.Holder () represents the owner of the Bind function. According to the previous analysis, we know that the owner is the object created by the function template defined by the Initialize function. This object holds a TCPWrap object. Let's expand ASSIGN_OR_RETURN_UNWRAP and have a look.
# define ASSIGN_OR_RETURN_UNWRAP (ptr, obj,...)\
Do {\
* ptr =\
Unwrap (obj);\
If (* ptr = = nullptr)\
Return _ _ VA_ARGS__;\
} while (0)
Template
TypeName* Unwrap (v8::Local object) {
/ / take out the value set by calling SetAlignedPointerFromInternalField
Void* pointer = object- > GetAlignedPointerFromInternalField (0)
Return static_cast (pointer)
}
After expanding, we see that the main logic is to take out the TCPWrap object that is saved in the C++ object. Then you can use the TCPWrap object.
Thank you for reading, these are the contents of "what is the general logic of C++ layer in nodejs source code analysis". After the study of this article, I believe you have a deeper understanding of what the general logic of C++ layer is in nodejs source code analysis, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 272
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.