SlideShare uma empresa Scribd logo
1 de 21
Baixar para ler offline
Extending node.js
using C++
Kenneth Geisshirt
kg@realm.io
Realm Inc.
@realm
http://github.com/Realm/
http://realm.io/
Today’s goal
• Learn
- the basics of V8 internals and API
- how to wrap C++ classes
• Go home and write an extension
Agenda
1.Why write extensions in
C++
2.My demo C++ classes
3.Building extensions
4.Wrapping classes
• Setting up class
• Instantiating objects
• Setters, getters, etc.
• Methods
• Callbacks/anonymous functions
• Exceptions
Why Extensions in C++?
• You get access to system resources
• I/O, peripheral devices, GPUs, etc,
• To get the performance of C++
• Cross-Language
• Common core features in C++, many language bindings
• Legacy code
• Tons of old and useful C/C++/Fortran code
Demo C++ Classes
• Person
• firstname()
• lastname()
• birthday()
• to_str()
• Book
• add(Person* p)
• Person *lookup(string
name)
• operator [size_t index]
• remove(size_t index)
• size_t size()
Gettersandsetters
https://github.com/kneth/DemoNodeExtension
V8 concepts
• Isolate is an isolated instance of V8
• Handles are references to JavaScript objects, and V8’s garbage collector
reclaims them
• Local handles are allocated on the stack; life-time is scope based
• Persistent handles are allocated on the heap; life-time can span multiple
function calls
• You don’t return an object - you set the return value using
GetReturnValue().Set()
• and you cannot return a Local object (I’ll return to it later on)
• V8 has classes to represent JavaScript types (String, Number, Array,
Object, …)
Breaking changes
0.10 →0.12
• V8 API changes in node.js 0.12 (February 2015)
• How to return values from C++ to JavaScript
• Type name for methods’ arguments
• Creating objects require an Isolate
• String encoding is strict (UTF-8 is common)
• Extensions cannot support both 0.10 and 0.12+
• https://strongloop.com/strongblog/node-js-v0-12-c-apis-
breaking/
Building extensions
• Wrapping classes
(person.cpp →
person_wrap.cpp, …)
• Build process described in
bindings.gyp
• node-gyp configure build
{
'targets': [{
'target_name': 'funstuff',
'sources': [ 'person.cpp', 'person_wrap.cpp', 'book.cpp',
'book_wrap.cpp', 'funstuff.cpp' ],
'xcode_settings': {
'OTHER_CFLAGS': [ '-mmacosx-version-min=10.8', '-std=c++11',
'-stdlib=libc++', '-fexceptions', '-frtti' ]
}
}]
}
Name of extension
OS X specific options
#include <node.h>
#include "person_wrap.hpp"
#include "book_wrap.hpp"
using namespace v8;
void InitAll (Handle<Object> exports) {
PersonWrap::Init(exports);
BookWrap::Init(exports);
}
NODE_MODULE(funstuff, InitAll)
Wrapping a class
• Wrapper classes inherent
from node::ObjectWrap
• All methods are static
#include <node.h>
#include <node_object_wrap.h>
#include "book.hpp"
#include "person.hpp"
class BookWrap : public node::ObjectWrap {
public:
static void Init(v8::Handle<v8::Object> exports);
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
BookWrap();
private:
~BookWrap();
Book* m_book;
static v8::Persistent<v8::Function> Constructor;
};
Add class to V8
Helper to create new objects
The class to wrap
Adding a
class to V8
• Calling BookWrap::Init() to register/add the
class
• Sets up constructor, methods, and basic
infrastructure
void BookWrap::Init(Handle<Object> exports) {
Isolate* isolate = exports->GetIsolate();
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, BookWrap::New);
tpl->SetClassName(String::NewFromUtf8(isolate, "Book"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
NODE_SET_PROTOTYPE_METHOD(tpl, “add", Add);
tpl->InstanceTemplate()->SetIndexedPropertyHandler(Getter, Setter,
0, Deleter, Enumerator);
Constructor.Reset(isolate, tpl->GetFunction());
exports->Set(String::NewFromUtf8(isolate, "Book"), tpl->GetFunction());
}
Setting the class name
Adding a method
Getter, setter, etc.
Preparing
constructor
var funstuff = require('./build/Release/funstuff');
Instantiate
an object
void BookWrap::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
if (args.IsConstructCall()) {
if (args.Length() == 0) {
BookWrap* bw = new BookWrap();
Book *b = new Book();
bw->m_book = b;
bw->Wrap(args.This());
args.GetReturnValue().Set(args.This());
}
}
Create wrapper and object
Add wrapper to V8 runtime
Return the object
var book = new funstuff.Book();
Methods
• Methods are implemented in C++
• Input validation is important (IsString,
IsNumber, …)
void BookWrap::Length(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate);
BookWrap* bw = ObjectWrap::Unwrap<BookWrap>(args.This());
const int count = bw->m_book->size();
Local<Integer> result = Integer::New(isolate, count);
args.GetReturnValue().Set(result);
}
var book = new funstuff.Book();
console.log('Book: ' + book.length());
Arguments: args.Length(), args[0]
Get this as wrapper object
Create an object to return
Return the new object
Get current scope
Instantiate objects
• Instantiating wrapper object in C++
• Method of one class returns object of other class
• For example: var person = book[4];
Handle<Object> PersonWrap::New(Isolate* isolate, Book* b, uint32_t index) {
EscapableHandleScope scope(isolate);
Handle<Value> argv[] = { Boolean::New(isolate, true) };
Local<Function> cons = Local<Function>::New(isolate, Constructor);
Handle<Object> obj = cons->NewInstance(1, argv);
PersonWrap* pw = PersonWrap::Unwrap<PersonWrap>(obj);
pw->m_person = (*b)[size_t(index)];
return scope.Escape(obj);
}
Dummy argument
Call constructor:
PersonWrap::New(const FunctionCallbackInfo<Value>& args)Add object to current scope
Indexed getters
and setters
book[6] = new Person();
var person = book[4];
void BookWrap::Getter(uint32_t index, const PropertyCallbackInfo<Value>& info) {
Isolate* isolate = info.GetIsolate();
HandleScope scope(isolate);
BookWrap* bw = ObjectWrap::Unwrap<BookWrap>(info.This());
Book* b = bw->m_book;
if (index >= b->size()) {
isolate->ThrowException(Exception::RangeError(String::NewFromUtf8(isolate,
"invalid row index")));
info.GetReturnValue().SetUndefined();
}
else {
Handle<Object> result = PersonWrap::New(isolate, b, index);
info.GetReturnValue().Set(result);
}
}
Instantiate a wrapper object and return it
Unwrap this and get C++ object
Validate input (index is in range)
void BookWrap::Setter(uint32_t index, Local<Value> value,
const PropertyCallbackInfo<Value>& info)
Value to set; remember to validate!
Accessors
• Accessors are useful for known properties
• C++ isn’t dynamic as JavaScript
• Added to V8 during initialisation (PersonWrap::Init())
var person = new funstuff.Person();
person.firstname = “Arthur”;
tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "firstname"),
PersonWrap::FirstnameGetter, PersonWrap::FirstnameSetter);
void PersonWrap::FirstnameGetter(Local<String> property,
const PropertyCallbackInfo<Value>& info) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
PersonWrap *pw = ObjectWrap::Unwrap<PersonWrap>(info.This());
Person *p = pw->m_person;
info.GetReturnValue().Set(String::NewFromUtf8(isolate, p->firstname().c_str()));
}
Callbacks
• Callbacks and anonymous functions are JavaScript
in a nutshell
• Functions are objects: Function is used in V8
book.each(function (p) {
console.log("Firstname: " + p.firstname);
});
void BookWrap::Each(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate);
Book* book = ObjectWrap::Unwrap<BookWrap>(args.This())->m_book;
if (args.Length() == 1) {
if (args[0]->IsFunction()) {
Local<Function> fun = Local<Function>::Cast(args[0]);
for(uint32_t i = 0; i < book->size(); ++i) {
Local<Object> pw = PersonWrap::New(isolate, book, i);
Local<Value> argv[1] = { pw };
fun->Call(Null(isolate), 1, argv);
}
args.GetReturnValue().SetUndefined();
return;
}
}
}
The anonymous function
Set up arguments
Call the function
Throwing Exceptions
• Throwing a C++ exception is a no-go
• set node.js’ state to “exception”
• when returning to JavaScript an exception is thrown
• V8 has a limited number of exceptions: RangeError,
ReferenceError, SyntaxError, TypeError, Error
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
// …
isolate->ThrowException(Exception::SyntaxError(String::NewFromUtf8(isolate,
"No arguments expected")));
args.GetReturnValue().SetUndefined();
return;
Catching
Exceptions
• Callbacks might throw an exception
• V8 has a TryCatch class to check for it
try {
var s = book.apply(function (b) {
throw { msg: "Error" };
});
console.log(" Length: " + s);
}
catch (e) {
console.log(" Exception caught: " + e.msg);
}
void BookWrap::Apply(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope scope(isolate);
Local<Function> fun = Local<Function>::Cast(args[0]);
Handle<Value> argv[] = { args.This() };
TryCatch trycatch;
Handle<Value> v = fun->Call(Null(isolate), 1, argv);
if (trycatch.HasCaught()) {
trycatch.ReThrow();
}
args.GetReturnValue().Set(v);
}
If HasCaught() is true, an JS exception was thrown
Set the node.s’ “exception” state
NAN
• Native Abstraction for Node (NAN) makes it easier
to write extensions
• Hides breaking changes in the V8 API
- Your extension will support many versions!
• Functions and macros for common tasks
• https://github.com/nodejs/nan
Observations
• Extensions do not have to be a one-to-one mapping
• A lot of code to do input validation
• JavaScript isn’t a strongly typed language
• Unit testing is very important
• C++ has classes - JavaScript doesn’t
• Awkward for JavaScript programmers
• Crossing language barrier during call is hard for debuggers
Learn more
• Check out my demo: https://github.com/kneth/
DemoNodeExtension
• Google’s documentation: https://
developers.google.com/v8/embed?hl=en
• JavaScript - The Good Parts. D. Crockford. O’Reilly
Media, 2008.
• Any modern C++ text book 😱
http://realm
.io
W
e
are
hiring

Mais conteúdo relacionado

Mais procurados

ooc - OSDC 2010 - Amos Wenger
ooc - OSDC 2010 - Amos Wengerooc - OSDC 2010 - Amos Wenger
ooc - OSDC 2010 - Amos Wenger
Amos Wenger
 
.NET Multithreading and File I/O
.NET Multithreading and File I/O.NET Multithreading and File I/O
.NET Multithreading and File I/O
Jussi Pohjolainen
 
20100712-OTcl Command -- Getting Started
20100712-OTcl Command -- Getting Started20100712-OTcl Command -- Getting Started
20100712-OTcl Command -- Getting Started
Teerawat Issariyakul
 
Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! 
aleks-f
 

Mais procurados (20)

Compose Async with RxJS
Compose Async with RxJSCompose Async with RxJS
Compose Async with RxJS
 
Virtual machine and javascript engine
Virtual machine and javascript engineVirtual machine and javascript engine
Virtual machine and javascript engine
 
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data EcosystemWprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
Wprowadzenie do technologii Big Data / Intro to Big Data Ecosystem
 
連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」連邦の白いヤツ 「Objective-C」
連邦の白いヤツ 「Objective-C」
 
Node Architecture and Getting Started with Express
Node Architecture and Getting Started with ExpressNode Architecture and Getting Started with Express
Node Architecture and Getting Started with Express
 
Swift after one week of coding
Swift after one week of codingSwift after one week of coding
Swift after one week of coding
 
Building fast interpreters in Rust
Building fast interpreters in RustBuilding fast interpreters in Rust
Building fast interpreters in Rust
 
ooc - OSDC 2010 - Amos Wenger
ooc - OSDC 2010 - Amos Wengerooc - OSDC 2010 - Amos Wenger
ooc - OSDC 2010 - Amos Wenger
 
.NET Multithreading and File I/O
.NET Multithreading and File I/O.NET Multithreading and File I/O
.NET Multithreading and File I/O
 
Advanced Object-Oriented JavaScript
Advanced Object-Oriented JavaScriptAdvanced Object-Oriented JavaScript
Advanced Object-Oriented JavaScript
 
Letswift19-clean-architecture
Letswift19-clean-architectureLetswift19-clean-architecture
Letswift19-clean-architecture
 
Cascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the StreamsCascadia.js: Don't Cross the Streams
Cascadia.js: Don't Cross the Streams
 
Rust ⇋ JavaScript
Rust ⇋ JavaScriptRust ⇋ JavaScript
Rust ⇋ JavaScript
 
Proxies are Awesome!
Proxies are Awesome!Proxies are Awesome!
Proxies are Awesome!
 
20100712-OTcl Command -- Getting Started
20100712-OTcl Command -- Getting Started20100712-OTcl Command -- Getting Started
20100712-OTcl Command -- Getting Started
 
The Ring programming language version 1.3 book - Part 84 of 88
The Ring programming language version 1.3 book - Part 84 of 88The Ring programming language version 1.3 book - Part 84 of 88
The Ring programming language version 1.3 book - Part 84 of 88
 
A JIT Smalltalk VM written in itself
A JIT Smalltalk VM written in itselfA JIT Smalltalk VM written in itself
A JIT Smalltalk VM written in itself
 
NS2 Object Construction
NS2 Object ConstructionNS2 Object Construction
NS2 Object Construction
 
Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! Look Ma, “update DB to HTML5 using C++”, no hands! 
Look Ma, “update DB to HTML5 using C++”, no hands! 
 
From C++ to Objective-C
From C++ to Objective-CFrom C++ to Objective-C
From C++ to Objective-C
 

Semelhante a Node.js extensions in C++

FI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS BasicsFI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS Basics
Petr Dvorak
 
Objective-C Survives
Objective-C SurvivesObjective-C Survives
Objective-C Survives
S Akai
 

Semelhante a Node.js extensions in C++ (20)

Building High Performance Android Applications in Java and C++
Building High Performance Android Applications in Java and C++Building High Performance Android Applications in Java and C++
Building High Performance Android Applications in Java and C++
 
Raffaele Rialdi
Raffaele RialdiRaffaele Rialdi
Raffaele Rialdi
 
How to Write Node.js Module
How to Write Node.js ModuleHow to Write Node.js Module
How to Write Node.js Module
 
The Present and Future of the Web Platform
The Present and Future of the Web PlatformThe Present and Future of the Web Platform
The Present and Future of the Web Platform
 
constructorsfjy5ediykEASFul;IUWORHusi;gfb.pptx
constructorsfjy5ediykEASFul;IUWORHusi;gfb.pptxconstructorsfjy5ediykEASFul;IUWORHusi;gfb.pptx
constructorsfjy5ediykEASFul;IUWORHusi;gfb.pptx
 
Introduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicoxIntroduction to web programming for java and c# programmers by @drpicox
Introduction to web programming for java and c# programmers by @drpicox
 
C++ Advanced Features
C++ Advanced FeaturesC++ Advanced Features
C++ Advanced Features
 
Look Mommy, No GC! (TechDays NL 2017)
Look Mommy, No GC! (TechDays NL 2017)Look Mommy, No GC! (TechDays NL 2017)
Look Mommy, No GC! (TechDays NL 2017)
 
C++ Advanced Features
C++ Advanced FeaturesC++ Advanced Features
C++ Advanced Features
 
Node.js System: The Landing
Node.js System: The LandingNode.js System: The Landing
Node.js System: The Landing
 
JavaScript in 2016 (Codemotion Rome)
JavaScript in 2016 (Codemotion Rome)JavaScript in 2016 (Codemotion Rome)
JavaScript in 2016 (Codemotion Rome)
 
JavaScript in 2016
JavaScript in 2016JavaScript in 2016
JavaScript in 2016
 
Android ndk
Android ndkAndroid ndk
Android ndk
 
Angular2 for Beginners
Angular2 for BeginnersAngular2 for Beginners
Angular2 for Beginners
 
MFF UK - Introduction to iOS
MFF UK - Introduction to iOSMFF UK - Introduction to iOS
MFF UK - Introduction to iOS
 
FI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS BasicsFI MUNI 2012 - iOS Basics
FI MUNI 2012 - iOS Basics
 
Objective-C Survives
Objective-C SurvivesObjective-C Survives
Objective-C Survives
 
Python_Unit_2 OOPS.pptx
Python_Unit_2  OOPS.pptxPython_Unit_2  OOPS.pptx
Python_Unit_2 OOPS.pptx
 
JSLT: JSON querying and transformation
JSLT: JSON querying and transformationJSLT: JSON querying and transformation
JSLT: JSON querying and transformation
 
Static code analysis: what? how? why?
Static code analysis: what? how? why?Static code analysis: what? how? why?
Static code analysis: what? how? why?
 

Mais de Kenneth Geisshirt

Naturvidenskabsfestival 2012
Naturvidenskabsfestival 2012Naturvidenskabsfestival 2012
Naturvidenskabsfestival 2012
Kenneth Geisshirt
 
JavaScript/Emacs integration
JavaScript/Emacs integrationJavaScript/Emacs integration
JavaScript/Emacs integration
Kenneth Geisshirt
 

Mais de Kenneth Geisshirt (15)

Building parsers in JavaScript
Building parsers in JavaScriptBuilding parsers in JavaScript
Building parsers in JavaScript
 
Open Source in Real Life
Open Source in Real LifeOpen Source in Real Life
Open Source in Real Life
 
Building mobile apps with Realm for React Native
Building mobile apps with Realm for React NativeBuilding mobile apps with Realm for React Native
Building mobile apps with Realm for React Native
 
micro:bit and JavaScript
micro:bit and JavaScriptmicro:bit and JavaScript
micro:bit and JavaScript
 
Tales from the dark side: developing SDKs at scale
Tales from the dark side: developing SDKs at scaleTales from the dark side: developing SDKs at scale
Tales from the dark side: developing SDKs at scale
 
Android things
Android thingsAndroid things
Android things
 
Is the database a solved problem?
Is the database a solved problem?Is the database a solved problem?
Is the database a solved problem?
 
Unleash your inner console cowboy
Unleash your inner console cowboyUnleash your inner console cowboy
Unleash your inner console cowboy
 
Sociale netværk
Sociale netværkSociale netværk
Sociale netværk
 
Unleash your inner console cowboy
Unleash your inner console cowboyUnleash your inner console cowboy
Unleash your inner console cowboy
 
Naturvidenskabsfestival 2012
Naturvidenskabsfestival 2012Naturvidenskabsfestival 2012
Naturvidenskabsfestival 2012
 
Hadoop - the data scientist's toolbox
Hadoop - the data scientist's toolboxHadoop - the data scientist's toolbox
Hadoop - the data scientist's toolbox
 
JavaScript/Emacs integration
JavaScript/Emacs integrationJavaScript/Emacs integration
JavaScript/Emacs integration
 
Introduction to JavaScript for Modern Software Development
Introduction to JavaScript for Modern Software DevelopmentIntroduction to JavaScript for Modern Software Development
Introduction to JavaScript for Modern Software Development
 
Kendthed og vigtighed
Kendthed og vigtighedKendthed og vigtighed
Kendthed og vigtighed
 

Último

Último (20)

%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
%in kaalfontein+277-882-255-28 abortion pills for sale in kaalfontein
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
%in Bahrain+277-882-255-28 abortion pills for sale in Bahrain
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park %in kempton park+277-882-255-28 abortion pills for sale in kempton park
%in kempton park+277-882-255-28 abortion pills for sale in kempton park
 
8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students8257 interfacing 2 in microprocessor for btech students
8257 interfacing 2 in microprocessor for btech students
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
call girls in Vaishali (Ghaziabad) 🔝 >༒8448380779 🔝 genuine Escort Service 🔝✔️✔️
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
10 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 202410 Trends Likely to Shape Enterprise Technology in 2024
10 Trends Likely to Shape Enterprise Technology in 2024
 
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdfAzure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
Azure_Native_Qumulo_High_Performance_Compute_Benchmarks.pdf
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
Exploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdfExploring the Best Video Editing App.pdf
Exploring the Best Video Editing App.pdf
 
Pharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodologyPharm-D Biostatistics and Research methodology
Pharm-D Biostatistics and Research methodology
 
%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand%in Midrand+277-882-255-28 abortion pills for sale in midrand
%in Midrand+277-882-255-28 abortion pills for sale in midrand
 
Define the academic and professional writing..pdf
Define the academic and professional writing..pdfDefine the academic and professional writing..pdf
Define the academic and professional writing..pdf
 
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) SolutionIntroducing Microsoft’s new Enterprise Work Management (EWM) Solution
Introducing Microsoft’s new Enterprise Work Management (EWM) Solution
 

Node.js extensions in C++

  • 1. Extending node.js using C++ Kenneth Geisshirt kg@realm.io Realm Inc. @realm http://github.com/Realm/ http://realm.io/
  • 2. Today’s goal • Learn - the basics of V8 internals and API - how to wrap C++ classes • Go home and write an extension
  • 3. Agenda 1.Why write extensions in C++ 2.My demo C++ classes 3.Building extensions 4.Wrapping classes • Setting up class • Instantiating objects • Setters, getters, etc. • Methods • Callbacks/anonymous functions • Exceptions
  • 4. Why Extensions in C++? • You get access to system resources • I/O, peripheral devices, GPUs, etc, • To get the performance of C++ • Cross-Language • Common core features in C++, many language bindings • Legacy code • Tons of old and useful C/C++/Fortran code
  • 5. Demo C++ Classes • Person • firstname() • lastname() • birthday() • to_str() • Book • add(Person* p) • Person *lookup(string name) • operator [size_t index] • remove(size_t index) • size_t size() Gettersandsetters https://github.com/kneth/DemoNodeExtension
  • 6. V8 concepts • Isolate is an isolated instance of V8 • Handles are references to JavaScript objects, and V8’s garbage collector reclaims them • Local handles are allocated on the stack; life-time is scope based • Persistent handles are allocated on the heap; life-time can span multiple function calls • You don’t return an object - you set the return value using GetReturnValue().Set() • and you cannot return a Local object (I’ll return to it later on) • V8 has classes to represent JavaScript types (String, Number, Array, Object, …)
  • 7. Breaking changes 0.10 →0.12 • V8 API changes in node.js 0.12 (February 2015) • How to return values from C++ to JavaScript • Type name for methods’ arguments • Creating objects require an Isolate • String encoding is strict (UTF-8 is common) • Extensions cannot support both 0.10 and 0.12+ • https://strongloop.com/strongblog/node-js-v0-12-c-apis- breaking/
  • 8. Building extensions • Wrapping classes (person.cpp → person_wrap.cpp, …) • Build process described in bindings.gyp • node-gyp configure build { 'targets': [{ 'target_name': 'funstuff', 'sources': [ 'person.cpp', 'person_wrap.cpp', 'book.cpp', 'book_wrap.cpp', 'funstuff.cpp' ], 'xcode_settings': { 'OTHER_CFLAGS': [ '-mmacosx-version-min=10.8', '-std=c++11', '-stdlib=libc++', '-fexceptions', '-frtti' ] } }] } Name of extension OS X specific options #include <node.h> #include "person_wrap.hpp" #include "book_wrap.hpp" using namespace v8; void InitAll (Handle<Object> exports) { PersonWrap::Init(exports); BookWrap::Init(exports); } NODE_MODULE(funstuff, InitAll)
  • 9. Wrapping a class • Wrapper classes inherent from node::ObjectWrap • All methods are static #include <node.h> #include <node_object_wrap.h> #include "book.hpp" #include "person.hpp" class BookWrap : public node::ObjectWrap { public: static void Init(v8::Handle<v8::Object> exports); static void New(const v8::FunctionCallbackInfo<v8::Value>& args); BookWrap(); private: ~BookWrap(); Book* m_book; static v8::Persistent<v8::Function> Constructor; }; Add class to V8 Helper to create new objects The class to wrap
  • 10. Adding a class to V8 • Calling BookWrap::Init() to register/add the class • Sets up constructor, methods, and basic infrastructure void BookWrap::Init(Handle<Object> exports) { Isolate* isolate = exports->GetIsolate(); Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, BookWrap::New); tpl->SetClassName(String::NewFromUtf8(isolate, "Book")); tpl->InstanceTemplate()->SetInternalFieldCount(1); NODE_SET_PROTOTYPE_METHOD(tpl, “add", Add); tpl->InstanceTemplate()->SetIndexedPropertyHandler(Getter, Setter, 0, Deleter, Enumerator); Constructor.Reset(isolate, tpl->GetFunction()); exports->Set(String::NewFromUtf8(isolate, "Book"), tpl->GetFunction()); } Setting the class name Adding a method Getter, setter, etc. Preparing constructor var funstuff = require('./build/Release/funstuff');
  • 11. Instantiate an object void BookWrap::New(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); if (args.IsConstructCall()) { if (args.Length() == 0) { BookWrap* bw = new BookWrap(); Book *b = new Book(); bw->m_book = b; bw->Wrap(args.This()); args.GetReturnValue().Set(args.This()); } } Create wrapper and object Add wrapper to V8 runtime Return the object var book = new funstuff.Book();
  • 12. Methods • Methods are implemented in C++ • Input validation is important (IsString, IsNumber, …) void BookWrap::Length(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); HandleScope scope(isolate); BookWrap* bw = ObjectWrap::Unwrap<BookWrap>(args.This()); const int count = bw->m_book->size(); Local<Integer> result = Integer::New(isolate, count); args.GetReturnValue().Set(result); } var book = new funstuff.Book(); console.log('Book: ' + book.length()); Arguments: args.Length(), args[0] Get this as wrapper object Create an object to return Return the new object Get current scope
  • 13. Instantiate objects • Instantiating wrapper object in C++ • Method of one class returns object of other class • For example: var person = book[4]; Handle<Object> PersonWrap::New(Isolate* isolate, Book* b, uint32_t index) { EscapableHandleScope scope(isolate); Handle<Value> argv[] = { Boolean::New(isolate, true) }; Local<Function> cons = Local<Function>::New(isolate, Constructor); Handle<Object> obj = cons->NewInstance(1, argv); PersonWrap* pw = PersonWrap::Unwrap<PersonWrap>(obj); pw->m_person = (*b)[size_t(index)]; return scope.Escape(obj); } Dummy argument Call constructor: PersonWrap::New(const FunctionCallbackInfo<Value>& args)Add object to current scope
  • 14. Indexed getters and setters book[6] = new Person(); var person = book[4]; void BookWrap::Getter(uint32_t index, const PropertyCallbackInfo<Value>& info) { Isolate* isolate = info.GetIsolate(); HandleScope scope(isolate); BookWrap* bw = ObjectWrap::Unwrap<BookWrap>(info.This()); Book* b = bw->m_book; if (index >= b->size()) { isolate->ThrowException(Exception::RangeError(String::NewFromUtf8(isolate, "invalid row index"))); info.GetReturnValue().SetUndefined(); } else { Handle<Object> result = PersonWrap::New(isolate, b, index); info.GetReturnValue().Set(result); } } Instantiate a wrapper object and return it Unwrap this and get C++ object Validate input (index is in range) void BookWrap::Setter(uint32_t index, Local<Value> value, const PropertyCallbackInfo<Value>& info) Value to set; remember to validate!
  • 15. Accessors • Accessors are useful for known properties • C++ isn’t dynamic as JavaScript • Added to V8 during initialisation (PersonWrap::Init()) var person = new funstuff.Person(); person.firstname = “Arthur”; tpl->InstanceTemplate()->SetAccessor(String::NewFromUtf8(isolate, "firstname"), PersonWrap::FirstnameGetter, PersonWrap::FirstnameSetter); void PersonWrap::FirstnameGetter(Local<String> property, const PropertyCallbackInfo<Value>& info) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); PersonWrap *pw = ObjectWrap::Unwrap<PersonWrap>(info.This()); Person *p = pw->m_person; info.GetReturnValue().Set(String::NewFromUtf8(isolate, p->firstname().c_str())); }
  • 16. Callbacks • Callbacks and anonymous functions are JavaScript in a nutshell • Functions are objects: Function is used in V8 book.each(function (p) { console.log("Firstname: " + p.firstname); }); void BookWrap::Each(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); HandleScope scope(isolate); Book* book = ObjectWrap::Unwrap<BookWrap>(args.This())->m_book; if (args.Length() == 1) { if (args[0]->IsFunction()) { Local<Function> fun = Local<Function>::Cast(args[0]); for(uint32_t i = 0; i < book->size(); ++i) { Local<Object> pw = PersonWrap::New(isolate, book, i); Local<Value> argv[1] = { pw }; fun->Call(Null(isolate), 1, argv); } args.GetReturnValue().SetUndefined(); return; } } } The anonymous function Set up arguments Call the function
  • 17. Throwing Exceptions • Throwing a C++ exception is a no-go • set node.js’ state to “exception” • when returning to JavaScript an exception is thrown • V8 has a limited number of exceptions: RangeError, ReferenceError, SyntaxError, TypeError, Error Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); // … isolate->ThrowException(Exception::SyntaxError(String::NewFromUtf8(isolate, "No arguments expected"))); args.GetReturnValue().SetUndefined(); return;
  • 18. Catching Exceptions • Callbacks might throw an exception • V8 has a TryCatch class to check for it try { var s = book.apply(function (b) { throw { msg: "Error" }; }); console.log(" Length: " + s); } catch (e) { console.log(" Exception caught: " + e.msg); } void BookWrap::Apply(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); HandleScope scope(isolate); Local<Function> fun = Local<Function>::Cast(args[0]); Handle<Value> argv[] = { args.This() }; TryCatch trycatch; Handle<Value> v = fun->Call(Null(isolate), 1, argv); if (trycatch.HasCaught()) { trycatch.ReThrow(); } args.GetReturnValue().Set(v); } If HasCaught() is true, an JS exception was thrown Set the node.s’ “exception” state
  • 19. NAN • Native Abstraction for Node (NAN) makes it easier to write extensions • Hides breaking changes in the V8 API - Your extension will support many versions! • Functions and macros for common tasks • https://github.com/nodejs/nan
  • 20. Observations • Extensions do not have to be a one-to-one mapping • A lot of code to do input validation • JavaScript isn’t a strongly typed language • Unit testing is very important • C++ has classes - JavaScript doesn’t • Awkward for JavaScript programmers • Crossing language barrier during call is hard for debuggers
  • 21. Learn more • Check out my demo: https://github.com/kneth/ DemoNodeExtension • Google’s documentation: https:// developers.google.com/v8/embed?hl=en • JavaScript - The Good Parts. D. Crockford. O’Reilly Media, 2008. • Any modern C++ text book 😱 http://realm .io W e are hiring