Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the general logic of C++ layer in nodejs source code analysis?

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.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report