Nodejs C++/JS Boundary: Crossing The Rubicon

Nodejs C++/JS Boundary: Crossing The Rubicon

Most articles about Nodejs internals always talk about the C++/JS boundary and crossing it sorta thing. But most don't usually go in-depth to

Most articles about Nodejs internals always talk about the C++/JS boundary and crossing it sorta thing. But most don’t usually go in-depth to explain what crossing the C++/JS boundary really meant and what crossing it is all about.

In this article, we will take an in-depth look at the C++/JS boundary to know what crossing it entails.

What we will gain from this article: Node.js powers over a million startups and companies. It is the most used backend framework. We use it every day. Developers with Node.js skill are in high demand, so learning how Node.js works in-depth will go a long way to broaden our horizon on Nodejs and be confident when building Nodejs apps.

C++/JS: The Boundary between two worlds

It all starts with the compiler.

First, what is a compiler?

A compiler is a program that translates a piece of code into machine code.

Great!! into machine code. Remember that.

Compilers are complex programs, they are broken down into parts, each part has a specific job.

source code
    |
    v
lexical analyzer
    |
    v
  parser
    |
    v
code generation

lexical analyzer: This generates tokens from the source code.

parser: This generates AST (Abstract Syntax Tree) tree from the tokens.

code generation: This generates machine/assembly code from the AST.

Most compilers generate the assembly equivalent of the source code and leave the assembler to mash everything up into a binary soup.

Nodejs uses v8 JS engine to compile and execute JS code. I hope, we know what v8 is.

if we don’t, v8 is an open-source high-performance JavaScript compiler from Google.

Whenever we run a js file in Node.js like this:

node script.js

Nodejs passes the script to v8 using its APIs. v8 compiles the JS code in the provided script (script.js) and returns the assembly equivalent. Node.js then uses another v8 API to run the generated assembly code.

The compiler compiles the code to assembly and copies it to memory.

Looking at the above image, the JS code is compiled to assembly code.

To run the compiled code, it allocates a space on the memory, moves the code to the allocated space and jumps to the memory space.

At the jump, execution now begins from the compiled code. Hence, it has crossed a boundary.

The code being executed now isn’t a C++ code but JS code. All are now in assembly.

If the compiled JS code execution ends, it jumps back to the C++ code.

The C++ code and JS code here doesn’t mean the C++ source code or the JS source code. No. It is the assembly code generated from their source codes by the compiler is what is being executed. You can say C++ code and JS code to differentiate which assembly code being run.

Call from JS to C++

Functions in C++ source code can be called from a JS code.

Example:

// script.js
let f = 90
function send() {
    var f= 100
}
send()
sendMe()

In this code, we defined send function but there is no sendMe function.

The sendMe function will be defined in our C++ app:

// v8_demo.cpp
include "v8.h";
void sendMe() {
    cout << "Greetings from C++ land";
}
int main() {
    Maybe<Local> result = v8::Script::Compile('script.js');
    result->Run();
}

Note: the above snippets won’t run. Its just for demo purposes.

Here, we have the sendMe function.

See what happens. On execution, our v8_demo.cpp runs like this:

MEMORY
    ; v8_demo.cpp
x00    sendMe:
x01        push ""Greetings from C++ land""
x02        call cout
x03        ret
x04
x05    main:
x06        push "script.js"
x07        call Compile
x08        push eax
x09        call Run
x10
x11
x12
x13
x14
x15
x16
x17
x18
x19
x20

see the sendMe function is present. Execution starts from main and proceeds downwards. On x07, the script.js is compiled and pushed to memory.

MEMORY
    ; v8_demo.cpp
x00    sendMe:
x01        push ""Greetings from C++ land""
x02        call cout
x03        ret
x04
x05    main:
x06        push "script.js"
x07 ➥     call Compile
x08        push eax
x09        call Run
x10
x11     ;script.js
x12     mov 90,f
x13     send:
x14         push 100
x15     call send
x16     call sendMe
x17
x18
x19
x20

See our script.js assembly code in memory. :) Here, there is no C++ or JS code. Everything is in assembly. Like I said earlier, we can just demarcate like, here is assembly code from the C++ script and here is assembly code from JS script.

So, when Run x09 is executed,

MEMORY
    ; v8_demo.cpp
x00    sendMe:
x01        push ""Greetings from C++ land""
x02        call cout
x03        ret
x04
x05    main:
x06        push "script.js"
x07        call Compile
x08        push eax
x09 ➥     call Run
x10
x11     ;script.js
x12     mov 90,f
x13     send:
x14         push 100
x15     call send
x16     call sendMe
x17
x18
x19
x20

it jumps to the JS assembly code memory space x12.

Note: Run is a v8 API to run the compiled JS code after compilation.

MEMORY
    ; v8_demo.cpp
x00    sendMe:
x01        push ""Greetings from C++ land""
x02        call cout
x03        ret
x04
x05    main:
x06        push "script.js"
x07        call Compile
x08        push eax
x09        call Run
x10
x11     ;script.js
x12 ➥  mov 90,f
x13     send:
x14         push 100
x15     call send
x16     call sendMe
x17
x18
x19
x20

Here, the code we wrote in script.js is executed in assembly form.

When execution reach x15 call send, it jumps to x13 send: and executes its block, after that, it returns and calls sendMe.

MEMORY
    ; v8_demo.cpp
x00    sendMe:
x01        push ""Greetings from C++ land""
x02        call cout
x03        ret
x04
x05    main:
x06        push "script.js"
x07        call Compile
x08        push eax
x09        call Run
x10
x11     ;script.js
x12     mov 90,f
x13     send:
x14         push 100
x15     call send
x16 ➥  call sendMe
x17
x18
x19
x20

This function wasn’t defined in our script.js, but because it was defined in v8_demo.cpp, it is now available in memory. It can be called because the assembly form of script.js and v8_demo.cpp, now executes in one language and in the same memory space.

So, execution jumps to x00 sendMe:, the start of the sendMe function.

MEMORY
    ; v8_demo.cpp
x00 ➥ sendMe:
x01        push ""Greetings from C++ land""
x02        call cout
x03        ret
x04
x05    main:
x06        push "script.js"
x07        call Compile
x08        push eax
x09        call Run
x10
x11     ;script.js
x12     mov 90,f
x13     send:
x14         push 100
x15     call send
x16     call sendMe
x17
x18
x19
x20

:) Greetings from C++ land is displayed !!

So, this kind of jump is called Crossing the C++/JS boundary.

Likewise call from C++ to JS is feasible, provided the function is defined in JS land.

Conclusion

You see it is quite simple, no magic, no big deal. Whenever you hear "Crossing C++/JS", always picture everything running in assembly and in the same memory space.

In our next articles, we will dive in deep to see how some major Node.js APIs works underneath:

  • setTimeout
  • process.nextTick
  • setImmediate
  • Promise
  • setInterval

If you have any question regarding this or anything I should add, correct or remove, feel free to comment, email or DM me. Thanks !!! 👍

Angular 9 Tutorial: Learn to Build a CRUD Angular App Quickly

What's new in Bootstrap 5 and when Bootstrap 5 release date?

What’s new in HTML6

How to Build Progressive Web Apps (PWA) using Angular 9

What is new features in Javascript ES2020 ECMAScript 2020

Programming a Javascript Simon Game Tutorial

Programming a Javascript Simon Game Tutorial

In this javascript tutorial, I recorded myself live programming an html5 javascript simon game.

In this javascript tutorial, I recorded myself live programming an html5 javascript simon game.

For those who don't know, I'm a full stack web developer who has been in the industry for over 5 years now. There is a lot of things I have learned along the way and I'd like to share that knowledge with anyone wanting to learn!

like this video if you found it useful and would like to see more videos of the same content.

subscribe to my channel if you are trying to improve your abilities as a web developer, software engineer, or even if you are just learning to code.

Don't forget to turn on those bell notifications!

Understanding Memoization And Dynamic Programming in Javascript

Understanding Memoization And Dynamic Programming in Javascript

In this Javascript tutorial I will explain what memoization is, how to use it, when you should use memoization, how to use memoization, what dynamic programming is, how to use memoization in dynamic programming. Memoization is a big complicated word that you may have never even heard before, but you may be surprised to know that you are most likely already using memoization without even realizing it.

Memoization is a big complicated word that you may have never even heard before, but you may be surprised to know that you are most likely already using memoization without even realizing it. Memoization is just the act of caching values so that they can be calculated quicker in the future. Memoization is really useful in all parts of programming, but where it is most useful is in dynamic programming. In this video I will explain what memoization is, how to use it, and why it is so useful especially in dynamic programming.

🧠 Concepts Covered:

  • What memoization is
  • When you should use memoization
  • How to use memoization
  • What dynamic programming is
  • How to use memoization in dynamic programming

How to get started Internationalization in JavaScript with NodeJS

How to get started Internationalization in JavaScript with NodeJS

Tutorial showing how to use the Intl JS API in NodeJS (i18n). We'll install a module to unlock the Intl API languages for Node and test out RelativeTimeFormat to translate and localise relative times in JavaScript.

Tutorial showing how to use the Intl JS API in NodeJS (i18n). We'll install a module to unlock the Intl API languages for Node and test out RelativeTimeFormat to translate and localise relative times in JavaScript. I'll tell you how to get started with the built-in internationalization library in JS for Node 12 and higher. We'll change the locale to see how the translation works and test different BCP 47 language tags.

Internationalization is a difficult undertaking but using the Intl API is an easy way to get started, it's great to see this new API in the JS language and available for use. Soon, you'll be able to have confidence using it in the browser as modern browsers support the major Intl features. Have a look at the browser compatibility charts to see which browsers and versions of node are supported.

Use Intl.RelativeTimeFormat for language-sensitive relative time formatting.
#javascript #nodejs #webdevelopment

MDN Documentation:

https://developer.mozilla.org/en-US/d...

Full ICU NPM package:

https://www.npmjs.com/package/full-icu