1 # v8+: Node.js addon C++ to C boundary layer
2
3 This layer offers a way to write at least simple Node.js addons in C without
4 all the horrible C++ goop you'd otherwise be expected to use. That goop
5 still exists, but you don't have to write it. More importantly, you can
6 write your module in a sane programming environment, avoiding the confusing
7 and error-prone C++ semantics.
8
9 ## Usage
10
11 Unlike most Node.js modules, v8+ does nothing by itself. It is intended to
12 be used as a build-time dependency of your native addon, providing you with
13 an alternate programming environment.
14
15 For full docs, read the source code.
16
17 ## Node.js Support
18
19 v8+ works with, and has been tested to some extent with, Node.js 0.6.18 and
20 0.8.1. It most likely works with other micro versions in the 0.6 and 0.8
21 series as well. Note that this does not mean you can necessarily expect an
22 addon built against a particular minor release of Node.js to work with any
23 other minor release of Node.js.
24
25 ## Building and Installing
26
27 The v8+ source code is compiled into your module directly along with your
28 code. There is no separate v8+ library or node module, so the v8+ source,
29 tools, and makefiles are required to be present at the time your module is
30 built. They are not required at runtime.
31
32 Normally, your addon module will depend on the v8plus package and install it
33 using npm. The v8+ makefiles are set up to accommodate the installation of
34 v8+ anywhere `node(1)` would be able to find it using `require()` if it were
35 a normal JavaScript module, so simply including it as a dependency in your
36 `package.json` will work correctly. In addition, you will need to create a
37 (normally trivial) makefile for your module that includes the makefiles
38 distributed as part of v8+. Once you have done so, it is sufficient to run
39 `gmake` to generate the native loadable module used by Node.js.
40
41 The overall outline for creating a v8+ module looks something like this:
42
43 1. Write the C code that does whatever your module does. Be sure to
44 \#include "v8plus_glue.h". Do not include any other v8+ headers.
45
46 2. Create an appropriate `package.json` file. See below for details.
47
48 3. Create a skeleton makefile. See below for details.
49
50 4. Create a JSON file defining the error codes your module will use. See
51 Errors below.
52
53 You should not (and need not) modify either of the delivered makefiles;
54 override the definitions in Makefile.v8plus.defs in your makefile as
55 appropriate.
56
57 ### Packaging Considerations
58
59 There are two essential properties your `package.json` must contain in order
60 to use v8+ with npm:
61
62 1. A dependency on `v8plus`.
63
64 2. An appropriate script entry for building your module. It is strongly
65 recommended that you use something like the following:
66
67 "postinstall": "gmake $(eval echo ${MAKE_OVERRIDES})"
68
69 This will allow someone building your module to set make variables by adding
70 them to the `MAKE_OVERRIDES` environment variable; e.g.,
71
72 $ MAKE_OVERRIDES="CTFCONVERT=/bin/true CTFMERGE=/bin/true" npm install
73
74 ### Tying into the Makefiles
75
76 The makefiles shipped with v8+ do the great majority of the heavy lifting
77 for you. A minimally functional makefile for your addon must contain four
78 things:
79
80 1. Variable definitions for `V8PLUS` and `PREFIX_NODE`. Alternately, you
81 may choose to provide these on the command line or via the environment.
82 It is recommended that these assignments be made exactly as follows,
83 which will cause the addon to be built against the `node` that is found
84 first in your path:
85
86 PREFIX_NODE := $(shell dirname `bash -c 'hash node; hash -t node'`)/..
87 V8PLUS := $(shell $(PREFIX_NODE)/bin/node -e 'require("v8plus");')
88
89 Note that the mechanism for finding `node` will not work correctly if
90 yours is a symlink. This invocation of node(1) uses a v8+ mechanism to
91 locate v8+ sources anywhere that node(1) can find them and should not be
92 modified unless you want to test an alternate v8+.
93
94 2. The exact line:
95
96 include $(V8PLUS)/Makefile.v8plus.defs
97
98 3. Variable assignments specific to your module. In particular, you must
99 define `SRCS`, `MODULE`, and `ERRNO_JSON`. Additional customisation is
100 optional.
101
102 4. The exact line:
103
104 include $(V8PLUS)/Makefile.v8plus.targ
105
106 Additional arbitrary customisation is possible using standard makefile
107 syntax; most things that are useful to change already have variables defined
108 in `Makefile.v8plus.defs` whose values you may append to or override. For
109 example, you may cause additional system libraries to be linked in by
110 appending `-lname` to the `LIBS` variable. By default, the makefiles assume
111 that your sources are located in the `src` subdirectory of your module, and
112 that you want the sole output of the build process to be called
113 `$(MODULE).node` and located in the `lib` subdirectory. This can be changed
114 by overriding the `MODULE_DIR` variable.
115
116 A simple example makefile may be found in the `examples/` subdirectory, and
117 additional examples may be found in existing consumers; see Consumers below.
118 The GNU people also provide a good manual for make if you get really stuck;
119 see <http://www.gnu.org/software/make/manual/make.html>. In general,
120 writing the necessary makefile fragment is expected to be as easy as or
121 easier than the equivalent task using `node-waf` or `node-gyp`, so if you're
122 finding it unexpectedly difficult or complicated there's probably an easier
123 way.
124
125 The makefiles follow GNU make syntax; other makes may not work but patches
126 that correct this are generally welcome (in particular, Sun make and GNU
127 make have different and incompatible ways to set a variable from the output
128 of a shell command, and there is no way I know to accommodate both).
129
130 ### Binary Interface
131
132 By default, the resulting object is linked with the `-zdefs` option, which
133 will cause the build to fail if any unresolved symbols remain. In order to
134 accommodate this, a mapfile specifying the available global symbols in your
135 `node` binary is automatically generated as part of the build process. This
136 makes it much easier to debug missing libraries; otherwise, a module with
137 unresolved symbols will fail to load at runtime with no useful explanation.
138 Mapfile generation probably works only on illumos-derived systems. Patches
139 that add support for other linkers are welcome.
140
141 Your module will have all symbols (other than `init`, which is used directly
142 by Node.js) reduced to local visibility, which is strongly recommended. If
143 for some reason you want your module's symbols to be visible to Node.js or
144 to other modules, you will have to modify the script that generates the
145 mapfile. See the `$(MAPFILE)` target in `Makefile.v8plus.targ`.
146
147 ## API
148
149 Your module is an object factory that instantiates and returns native
150 objects, to which a fixed set of methods is attached as properties. The
151 constructor, destructor, and methods all correspond 1-1 with C functions.
152 In addition, you may create additional class methods associated with the
153 native module itself, each of which will also have a 1-1 relationship to a
154 set of C functions.
155
156 This functionality is generally sufficient to interface with the system in
157 useful ways, but it is by no means exhaustive. Architectural limitations
158 are noted throughout the documentation.
159
160 Subsequent sections describe the API in greater detail, along with most of
161 the C functions that v8+ provides. Some utility functions may not be listed
162 here; see `v8plus_glue.h` for additional commentary and functions that are
163 available to you.
164
165 ### Constructors, Methods, and Functions
166
167 The interface between your module and v8+ consists of a handful of objects
168 with fixed types and names. These are:
169
170 const v8plus_c_ctor_f v8plus_ctor = my_ctor;
171 const v8plus_c_dtor_f v8plus_dtor = my_dtor;
172 const char *v8plus_js_factory_name = "_new";
173 const char *v8plus_js_class_name = "MyObjectBinding";
174 const v8plus_method_descr_t v8plus_methods[] = {
175 {
176 md_name: "_my_method",
177 md_c_func: my_method
178 },
179 ...
180 };
181 const uint_t v8plus_method_count =
182 sizeof (v8plus_methods) / sizeof (v8plus_methods[0]);
183
184 const v8plus_static_descr_t v8plus_static_methods[] = {
185 {
186 sd_name: "_my_function",
187 sd_c_func: my_function
188 },
189 ...
190 };
191 const uint_t v8plus_static_method_count =
192 sizeof (v8plus_static_methods) / sizeof (v8plus_static_methods[0]);
193
194 All of these must be present even if they have zero length or are NULL. The
195 prototypes and semantics of each function type are as follows:
196
197 ### nvlist_t *v8plus_c_ctor_f(const nvlist_t *ap, void **opp)
198
199 The constructor is responsible for creating the C object corresponding to
200 the native JavaScript object being created. It is not a true constructor in
201 that you are actually an object factory; the C++ function associated with
202 the JavaScript constructor is called for you. Your encoded arguments are in
203 `ap`. Allocate and populate a C object, stuff it into `*opp`, and return
204 `v8plus_void()`. If you need to throw an exception you can do so by
205 returning `v8plus_error()` or one of its wrappers, or by setting
206 `_v8plus_errno` using one of those functions and then returning an nvlist
207 with an `err` member representing a decorated exception.
208
209 ### void v8plus_c_dtor_f(void *op)
210
211 Free the C object `op` and anything else associated with it. Your object is
212 going away. This function may be empty if the constructor did not allocate
213 any memory (i.e., `op` is not a pointer to dynamically allocated memory).
214
215 ### nvlist_t *v8plus_c_method_f(void *op, const nvlist_t *ap)
216
217 When the JavaScript method is called in the context of your object, the
218 corresponding C function is invoked. `op` is the C object associated with
219 the JavaScript object, and `ap` is the encoded list of arguments to the
220 function. Return an encoded object with a `res` member, or use one of the
221 error/exception patterns.
222
223 ### nvlist_t *v8plus_c_static_method_f(const nvlist_t *ap)
224
225 In addition to methods on the native objects returned by your constructor,
226 you can also provide a set of functions on the native binding object itself.
227 This may be useful for providing bindings to libraries for which no object
228 representation makes sense, or that have functions that operate outside the
229 context of any particular object. Your arguments are once again encoded in
230 `ap`, and your return values are an object containing `res` or an error.
231
232 ### Argument Handling
233
234 When JavaScript objects cross the boundary from C++ to C, they are converted
235 from v8 C++ objects into C nvlists. This means that they are effectively
236 passed by value, unlike in JavaScript or in native addons written in C++.
237 The arguments to the JavaScript function are treated as an array and
238 marshalled into a single nvlist whose properties are named "0", "1", and so
239 on. Each such property is encoded as follows:
240
241 - numbers and Number objects (regardless of size): double
242 - strings and String objects: UTF-8 encoded C string
243 - booleans and Boolean objects: boolean_value
244 - undefined: boolean
245 - null: byte, value 0
246 - Objects, including Arrays: nvlist with own properties as members and the
247 member ".__v8plus_type" set to the object's JavaScript type name. Note
248 that the member name itself begins with a . to reduce the likelihood of a
249 collision with an actual JavaScript member name.
250 - JavaScript Functions are passed in a format suitable for use with
251 `nvlist_lookup_jsfunc()` and `v8plus_args()` with the V8PLUS_TYPE_JSFUNC
252 token. This type is restricted; see below.
253
254 Because JavaScript arrays may be sparse, we cannot use the libnvpair array
255 types. Consider them reserved for internal use. JavaScript Arrays are
256 represented as they really are in JavaScript: objects with properties whose
257 names happen to be integers.
258
259 Other data types cannot be represented and will result in a TypeError
260 being thrown. If your object has methods that need other argument types,
261 you cannot use v8+.
262
263 Side effects within the VM, including modification of the arguments, are
264 not supported. If you need them, you cannot use v8+.
265
266 While the standard libnvpair functions may be used to inspect the arguments
267 to a method or function, v8+ also provides the `v8plus_args()` and
268 `v8plus_typeof()` convenience functions, which simplify checking the types
269 and obtaining the values of arguments.
270
271 ### int v8plus_args(const nvlist_t *lp, uint_t flags, v8plus_type_t t, ...)
272
273 This function checks `lp` for the exact sequence of arguments specified by
274 the list of types provided in the parameter list. If `V8PLUS_ARG_F_NOEXTRA`
275 is set in `flags`, the list of arguments must match exactly, with no
276 additional arguments. The parameter list must be terminated by
277 `V8PLUS_TYPE_NONE`.
278
279 Following `flags` is a list of argument data types and, for most data types,
280 pointers to locations at which the native C value of that argument should be
281 stored. The following JavaScript argument data types are supported; for
282 each, the parameter immediately following the data type parameter must be of
283 the indicated C type. This parameter may be `NULL`, in which case the value
284 will not be stored anywhere.
285
286 - V8PLUS_TYPE_NONE: used to terminate the parameter list only
287 - V8PLUS_TYPE_STRING: char **
288 - V8PLUS_TYPE_NUMBER: double *
289 - V8PLUS_TYPE_BOOLEAN: boolean_t *
290 - V8PLUS_TYPE_JSFUNC: v8plus_jsfunc_t *
291 - V8PLUS_TYPE_OBJECT: nvlist_t **
292 - V8PLUS_TYPE_NULL: no parameter
293 - V8PLUS_TYPE_UNDEFINED: no parameter
294 - V8PLUS_TYPE_INVALID: data_type_t (see below)
295 - V8PLUS_TYPE_ANY: nvpair_t **
296 - V8PLUS_TYPE_STRNUMBER64: uint64_t *
297 - V8PLUS_TYPE_INL_OBJECT: illegal
298
299 In most cases, the behaviour is straightforward: the value pointer parameter
300 provides a location into which the C value of the specified argument should
301 be stored. If the entire argument list matches the template, each
302 argument's C value is stored in its respective location. If not, no values
303 are stored, in the return value locations, `_v8plus_errno` is set
304 appropriately, and -1 is returned.
305
306 Three data types warrant further explanation: an argument of type
307 `V8PLUS_TYPE_INVALID` is any argument that may or may not match one of the
308 acceptable types. Its nvpair data type tag is stored and the argument
309 treated as matching. The value is ignored. `V8PLUS_TYPE_STRNUMBER64` is
310 used with strings that should be interpreted as 64-bit unsigned integers.
311 If the argument is not a string, or is not parseable as a 64-bit unsigned
312 integer, the argument will be treated as a mismatch. Finally,
313 `V8PLUS_TYPE_INL_OBJECT` is not supported with `v8plus_args()`; JavaScript
314 objects in the argument list must be individually inspected as nvlists.
315
316 A simple example:
317
318 double_t d;
319 boolean_t b;
320 char *s;
321 v8plus_jsfunc_t f;
322
323 /*
324 * This function requires exactly four arguments: a number, a
325 * boolean, a string, and a callback function. It is not acceptable
326 * to pass superfluous arguments to it.
327 */
328 if (v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA,
329 V8PLUS_TYPE_NUMBER, &d,
330 V8PLUS_TYPE_BOOLEAN, &b,
331 V8PLUS_TYPE_STRING, &s,
332 V8PLUS_TYPE_JSFUNC, &f,
333 V8PLUS_TYPE_NONE) != 0)
334 return (NULL);
335
336 ### v8plus_type_t v8plus_typeof(const nvpair_t *pp)
337
338 This function simply returns the v8+ data type corresponding to the
339 name/value pair `pp`. If the value's type does not match the v8+ encoding
340 rules, `V8PLUS_TYPE_INVALID` is returned. This function cannot fail and
341 does not modify `_v8plus_errno`.
342
343 ### Returning Values
344
345 Similarly, when returning data across the boundary from C to C++, a
346 pointer to an nvlist must be returned. This object will be decoded in
347 the same manner as described above and returned to the JavaScript caller
348 of your method. Note that booleans, strings, and numbers will be encoded
349 as their primitive types, not objects. If you need to return something
350 containing these object types, you cannot use v8+. Other data types
351 cannot be represented. If you need to return them, you cannot use v8+.
352
353 The nvlist being returned must have one of two members: "res", an nvpair
354 containing the result of the call to be returned, or "err", an nvlist
355 containing members to be added to an exception. You may return a value of
356 any decodable type, and likewise may decorate an exception with properties
357 of any decodable type.
358
359 For convenience, you may return v8plus_void() instead of an nvlist,
360 which indicates successful execution of a function that returns nothing.
361
362 In addition, the `v8plus_obj()` routine is available for instantiating
363 JavaScript objects to return.
364
365 ### nvlist_t *v8plus_void(void)
366
367 This function clears `_v8plus_errno` and returns NULL. This is used to
368 indicate to internal v8+ code that the method or function should not return
369 a value.
370
371 ### nvlist_t *v8plus_obj(v8plus_type_t t, ...)
372
373 This function creates and populates an nvlist conforming to the encoding
374 rules of v8+ for returning a value or creating an exception. It can be used
375 to create anything from a single encoded value to arbitrarily nested
376 objects. It is essentially the inverse of `v8plus_args()` above, with a few
377 differences:
378
379 - It cannot be used to encode invalid or illegal data types.
380 - It accepts native C values, not pointers to them.
381 - Each value must be named.
382 - It can be used to encode nested objects inline using
383 `V8PLUS_TYPE_INL_OBJECT`, followed by type, name, value triples,
384 terminated with `V8PLUS_TYPE_NONE`.
385
386 This function can fail due to out-of-memory conditions, invalid or
387 unsupported data types, or, most commonly, programmer error in casting the
388 arguments to the correct type. *It is extremely important that data values,
389 particularly integers, be cast to the appropriate type (double) when passed
390 into this function!*
391
392 Following is a list of types and the C data types corresponding to their
393 values:
394
395 - V8PLUS_TYPE_NONE: used to terminate the parameter list only
396 - V8PLUS_TYPE_STRING: char *
397 - V8PLUS_TYPE_NUMBER: double
398 - V8PLUS_TYPE_BOOLEAN: boolean_t
399 - V8PLUS_TYPE_JSFUNC: v8plus_jsfunc_t
400 - V8PLUS_TYPE_OBJECT: nvlist_t *
401 - V8PLUS_TYPE_NULL: no parameter
402 - V8PLUS_TYPE_UNDEFINED: no parameter
403 - V8PLUS_TYPE_ANY: nvpair_t *
404 - V8PLUS_TYPE_STRNUMBER64: uint64_t
405 - V8PLUS_TYPE_INL_OBJECT: NONE-terminated type/value list
406
407 A simple example, in which we return a JavaScript object with two members,
408 one number and one embedded object with a 64-bit integer property. Note
409 that if this function fails, we will return `NULL` with `_v8plus_errno` set
410 appropriately, so v8+ will generate and throw an appropriate exception.
411
412 int x;
413 const char *s;
414
415 ...
416 return (v8plus_obj(
417 V8PLUS_TYPE_INL_OBJECT, "res",
418 V8PLUS_TYPE_NUMBER, "value", (double)x,
419 V8PLUS_TYPE_INL_OBJECT, "detail",
420 V8PLUS_TYPE_STRNUMBER64, "value64", s,
421 V8PLUS_TYPE_NONE,
422 V8PLUS_TYPE_NONE,
423 V8PLUS_TYPE_NONE));
424
425 The JSON representation of this object would be:
426
427 {
428 "res": {
429 "value": <x>,
430 "detail": {
431 "value64": "<s>"
432 }
433 }
434 }
435
436 ### v8plus_obj_setprops(nvlist_t *lp, v8plus_type_t t, ...)
437
438 You can also add or replace the values of properties in an existing nvlist,
439 whether created using `nvlist_alloc()` directly or via `v8plus_obj()`. The
440 effect is very similar to `nvlist_merge()`, where the second list is created
441 on the fly from your argument list. The interpretation of the argument list
442 is the same as for `v8plus_obj()`, and the two functions are implemented
443 using the same logic.
444
445 ### Exceptions
446
447 If you are unable to create an nvlist to hold exception data, or you want a
448 generic exception to be thrown, return the value returned by v8plus_error().
449 In this case, the error code will be translated to an exception type and the
450 message string will be used as the message member of the exception. Other
451 members will not be present in the exception unless you also return an
452 nvlist containing an 'err' member (or, from a constructor, any nvlist) Only
453 basic v8-provided exception types can be thrown; if your addon needs to
454 throw some other kind of exception, you will need to either use v8 directly
455 or catch and re-throw from a JavaScript wrapper.
456
457 ## Errors
458
459 The v8plus_errno_t enumerated type and a family of utility functions are
460 automatically generated by generrno.js from a simple JSON file. The schema
461 of this file is as follows:
462
463 {
464 "error_base": <string>,
465 "errors": [
466 {
467 "code": <string>,
468 "msg": <string>,
469 "exception": <string>
470 },
471 ... ]
472 }
473
474 For each entry in the errors array, an identifier V8PLUSERR_code will be
475 added to v8plus_errno_t. By convention, code should be all upper case. The
476 default error message (present in JavaScript exceptions if a more specific
477 error message is not provided to v8plus_error()) is given by the msg
478 property. The exception property must be one of "Error", "TypeError",
479 "ReferenceError", "RangeError", or "SyntaxError"; i.e., the standard
480 exception types available in v8. This is the type of exception that will be
481 generated and thrown when a C function returns NULL with this error code
482 set. In addition, the built-in error codes V8PLUSERR_NOMEM,
483 V8PLUSERR_YOUSUCK, and V8PLUSERR_UNKNOWN are available for your use,
484 indicating an out of memory condition, programmer error (e.g., failure of
485 something you would assert in JavaScript), and an error code that cannot be
486 translated, respectively.
487
488 Set the make variable ERRNO_JSON to the name of this file.
489
490 To set the value of `_v8plus_errno`, use one of the following functions. It
491 is a bug to manipulate this variable directly.
492
493 ### nvlist_t *v8plus_verror(v8plus_errno_t e, const char *fmt, va_list)
494
495 This is the varargs analogue to `v8plus_error()` and has identical
496 semantics. Use this if you want to wrap manipulation of the v8+ error state
497 within your own varargs functions.
498
499 ### nvlist_t *v8plus_error(v8plus_errno_t e, const char *fmt, ...)
500
501 This function sets the value of `_v8plus_errno` to `e` and sets the
502 associated error message string to the formatted string `fmt` using the
503 argument list that follows. The format string and arguments are interpreted
504 as by `vsnprintf(3c)`. NULL is returned, suitable for returning directly
505 from a C function that provides a method if no exception decoration is
506 required.
507
508 If `fmt` is NULL, a generic default message is used; for consumer-defined
509 error codes, that message is the one provided in `errno.json`.
510
511 ### nvlist_t *v8plus_nverr(int errno, const char *propname)
512
513 This function sets the value of `_v8plus_errno` to a value mapped from the
514 system error code `errno` and sets the error message to a non-localised
515 explanation of the problem. The string `propname`, if non-NULL, is
516 indicated in the message as the name of the nvlist property being
517 manipulated when the error occurred. NULL is returned.
518
519 ### nvlist_t *v8plus_syserr(int errno, const char *fmt, ...)
520
521 Analogous to `v8plus_error()`, this function instead sets the error code to
522 a mapped value derived from the system error code `errno`. Not all error
523 codes can be mapped; those that are not known are mapped onto
524 `V8PLUSERR_UNKNOWN`. This function's semantics are otherwise identical to
525 those of `v8plus_error()`.
526
527 ### void v8plus_panic(const char *fmt, ...) __NORETURN
528
529 This function indicates a fatal runtime error. The format string `fmt` and
530 subsequent arguments are interpreted as by `vsnprintf(3c)` and written to
531 standard error, which is then flushed. `abort(3c)` or similar is then
532 invoked to terminate the Node.js process in which the addon is running. Use
533 of this function should be limited to those circumstances in which an
534 internal inconsistency has been detected that renders further progress
535 hazardous to user data or impossible.
536
537 ### Asynchrony
538
539 There are two main types of asynchrony supported by v8+. The first is the
540 deferred work model (using `uv_queue_work()` or the deprecated
541 `eio_custom()` mechanisms) frequently written about and demonstrated by
542 various practitioners around the world. In this model, your method or
543 function takes a callback argument and returns immediately after enqueuing a
544 task to run on one of the threads in the Node.js worker thread pool. That
545 task consists of a C function to be run on the worker thread, which may not
546 use any V8 (or v8+) state, and a function to be run in the main event loop
547 thread when that task has completed. The latter function is normally
548 expected to invoke the caller's original callback. In v8+, this takes the
549 following form:
550
551 void *
552 async_worker(void *cop, void *ctxp)
553 {
554 my_object_t *op = cop;
555 my_context_t *cp = ctxp;
556 my_result_t *rp = ...;
557
558 /*
559 * In thread pool context -- do not call any of the
560 * following functions:
561 * v8plus_obj_hold()
562 * v8plus_obj_rele()
563 * v8plus_jsfunc_hold()
564 * v8plus_jsfunc_rele()
565 * v8plus_call()
566 * v8plus_method_call()
567 * v8plus_defer()
568 *
569 * If you touch anything inside op, you may need locking to
570 * protect against functions called in the main thread.
571 */
572 ...
573
574 return (rp);
575 }
576
577 void
578 async_completion(void *cop, void *ctxp, void *resp)
579 {
580 my_object_t *op = cop;
581 my_context_t *cp = ctxp;
582 my_result_t *rp = resp;
583 nvlist_t *cbap;
584 nvlist_t *cbrp;
585
586 ...
587 cbap = v8plus_obj(
588 V8PLUS_TYPE_WHATEVER, "0", rp->mr_value,
589 V8PLUS_TYPE_NONE);
590
591 if (cbap != NULL) {
592 cbrp = v8plus_call(cp->mc_callback, cbap);
593 nvlist_free(cbap);
594 nvlist_free(cbrp);
595 }
596
597 v8plus_jsfunc_rele(cp->mc_callback);
598 free(cp);
599 free(rp);
600 }
601
602 nvlist_t *
603 async(void *cop, const nvlist_t *ap)
604 {
605 my_object_t *op = cop;
606 v8plus_jsfunc_t cb;
607 my_context_t *cp = malloc(sizeof (my_context_t));
608 ...
609 if (v8plus_args(ap, 0, V8PLUS_TYPE_JSFUNC, &cb,
610 V8PLUS_TYPE_NONE) != 0) {
611 free(cp);
612 return (NULL);
613 }
614
615 v8plus_jsfunc_hold(cb);
616 cp->mc_callback = cb;
617 v8plus_defer(op, cp, async_worker, async_completion);
618
619 return (v8plus_void());
620 }
621
622 This mechanism uses `uv_queue_work()` and as such will tie up one of the
623 worker threads in the pool for as long as `async_worker` is running.
624
625 The other asynchronous mechanism is the Node.js `EventEmitter` model. This
626 model requires some assistance from JavaScript code, because v8+ native
627 objects do not inherit from `EventEmitter`. To make this work, you will
628 need to create a JavaScript object (the object your consumers actually use)
629 that inherits from `EventEmitter`, hang your native object off this object,
630 and populate the native object with an appropriate method that will cause
631 the JavaScript object to emit events when the native object invokes that
632 method. A simple example might look like this:
633
634 var util = require('util');
635 var binding = require('./native_binding');
636 var events = require('events');
637
638 function
639 MyObjectWrapper()
640 {
641 var self = this;
642
643 events.EventEmitter.call(this);
644 this._native = binding._create.apply(this,
645 Array.prototype.slice.call(arguments));
646 this._native._emit = function () {
647 var args = Array.prototype.slice.call(arguments);
648 self.emit.apply(self, args);
649 };
650 }
651 util.inherits(MyObjectWrapper, events.EventEmitter);
652
653 Then, in C code, you must arrange for libuv to call a C function in the
654 context of the main event loop. How to do this depends on what type of
655 asynchronous event you are waiting for; for example, the `uv_poll` mechanism
656 will call you back in the appropriate context when a file descriptor becomes
657 readable or writable. Because libuv is a C library, you can easily use
658 these interfaces directly in your v8+ addon. Your libuv callback might then
659 contain code looking something like this:
660
661 nvlist_t *eap;
662 nvlist_t *erp;
663 my_object_t *op = ...;
664 ...
665 eap = v8plus_obj(
666 V8PLUS_TYPE_STRING, "0", "my_event",
667 ...,
668 V8PLUS_TYPE_NONE);
669
670 if (eap != NULL) {
671 erp = v8plus_method_call(op, "_emit", eap);
672 nvlist_free(eap);
673 nvlist_free(erp);
674 }
675
676 This example will generate an event named "my_event" and propagate it to
677 listeners registered with the `MyObjectWrapper` instance. If additional
678 arguments are associated with the event, they may be added to `eap` and will
679 also be passed along to listeners as arguments to their callbacks.
680
681 ### void v8plus_obj_hold(const void *op)
682
683 Places a hold on the V8 representation of the specified C object. This is
684 rarely necessary; `v8plus_defer()` performs this action for you, but other
685 asynchronous mechanisms may require it. If you are returning from a method
686 call but have stashed a reference to the object somewhere and are not
687 calling `v8plus_defer()`, you must call this first. Holds and releases must
688 be balanced. Use of the object within a thread after releasing is a bug.
689
690 ### void v8plus_obj_rele(const void *op)
691
692 Releases a hold placed by `v8plus_obj_hold()`.
693
694 ### void v8plus_jsfunc_hold(v8plus_jsfunc_t f)
695
696 Places a hold on the V8 representation of the specified JavaScript function.
697 This is required when returning from a C function that has stashed a
698 reference to the function, typically to use it asynchronously as a callback.
699 All holds must be balanced with a release. Because a single hold is placed
700 on such objects when passed to you in an argument list (and released for you
701 when you return), it is legal to reference and even to invoke such a
702 function without first placing an additional hold on it.
703
704 ### void v8plus_jsfunc_rele(v8plus_jsfunc_t f)
705
706 Releases a hold placed by `v8plus_jsfunc_hold()`.
707
708 ### void v8plus_defer(void *op, void *ctx, worker, completion)
709
710 Enqueues work to be performed in the Node.js shared thread pool. The object
711 `op` and context `ctx` are passed as arguments to `worker` executing in a
712 thread from that pool. The same two arguments, along with the worker's
713 return value, are passed to `completion` executing in the main event loop
714 thread. See example above.
715
716 ### nvlist_t *v8plus_call(v8plus_jsfunc_t f, const nvlist_t *ap)
717
718 Calls the JavaScript function referred to by `f` with encoded arguments
719 `ap`. The return value is the encoded return value of the function. The
720 argument and return value encoding match the encodings that are used by C
721 functions that provide methods.
722
723 ### nvlist_t *v8plus_method_call(void *op, const char *name, const nvlist_t *ap)
724
725 Calls the method named by `name` in the native object `op` with encoded
726 argument list `ap`. The method must exist and must be a JavaScript
727 function. Such functions may be attached by JavaScript code as in the event
728 emitter example above. The effects of using this function to call a native
729 method are undefined.
730
731 ## FAQ
732
733 - Why?
734
735 Because C++ is garbage. Writing good software is challenging enough without
736 trying to understand a bunch of implicit side effects or typing templated
737 identifiers that can't fit in 80 columns without falling afoul of the
738 language's ambiguous grammar. Don't get me started.
739
740 - Why not use [FFI](https://github.com/rbranson/node-ffi)?
741
742 FFI is really cool; it offers us the ability to use C libraries without
743 writing bindings at all. However, it also exposes a lot of C nastiness to
744 JavaScript code, essentially placing the interface boundary in consuming
745 code itself. This pretty much breaks the JavaScript interface model --
746 for example, you can't really have a function that inspects the types of its
747 arguments -- and requires you to write an additional C library anyway if you
748 want or need to do something natively that's not quite what the C library
749 already does. Of course, one could use it to write "bindings" in JavaScript
750 that actually look like a JavaScript interface, which may end up being the
751 best answer, especially if those are autogenerated from CTF! In short, v8+
752 and FFI are different approaches to the problem. Use whichever fits your
753 need, and note that they're not mutually exclusive, either.
754
755 - What systems can I use this on?
756
757 [illumos](http://illumos.org) distributions, or possibly other platforms
758 with a working libnvpair. I'm sorry if your system doesn't have it; it's
759 open source and pretty easy to port.
760
761 There is an OSX port; see [the ZFS port's
762 implementation](http://code.google.com/p/maczfs/source/browse/#git%2Fusr%2Fsrc%2Flib%2Flibnvpair).
763 Unfortunately this port lacks the requisite support for floating-point data
764 (DATA_TYPE_DOUBLE) but you could easily add that from the illumos sources.
765
766 - What about node-waf and node-gyp?
767
768 Fuck python, fuck WAF, and fuck all the hipster douchebags for whom make is
769 too hard, too old, or "too Unixy". Make is simple, easy to use, and
770 extremely reliable. It was building big, important pieces of software when
771 your parents were young, and it Just Works. If you don't like using make
772 here, you probably don't want to use v8+ either, so just go away. Write
773 your CoffeeScript VM in something else, and gyp-scons-waf-rake your way to
774 an Instagram retirement in Bali with all your hipster douchebag friends.
775 Just don't bother me about it, because I don't care.
776
777 - Why is Node failing in dlopen()?
778
779 Most likely, your module has a typo or needs to be linked with a library.
780 Normally, shared objects like Node addons should be linked with -zdefs so that
781 these problems are found at build time, but Node doesn't deliver a mapfile
782 specifying its API so you're left with a bunch of undefined symbols you just
783 have to hope are defined somewhere in your node process's address space. If
784 they aren't, you're boned. LD_DEBUG=all will help you find the missing
785 symbol(s).
786
787 As of 0.0.2, v8+ builds a mapfile for your node binary at the time you build
788 your addon. It does not attempt to restrict the visibility of any symbols,
789 so you will not be warned if your addon is using private or deprecated
790 functionality in V8 or Node.js. Your build will, however, fail if you've
791 neglected to link in any required libraries, typo'd a symbol name, etc.
792
793 - Why use the old init() instead of NODE_MODULE()?
794
795 Because NODE_MODULE() is a macro that can't be passed another macro as the
796 name of your addon. Using it would therefore require the source to v8+ to
797 be generated at build time to match your module's name, which is
798 inconvenient. There may be a way to work around this.
799
800 - Why can't I see my exception's decorative properties in JavaScript?
801
802 Be careful when decorating exceptions. There are several built-in hidden
803 properties; if you decorate the exception with a property with the same
804 name, you will change the hidden property's value but it will still be
805 hidden. This almost certainly is not what you want, so you should prefix
806 the decorative property names with something unique to your module to avoid
807 stepping on V8's (or JavaScript's) property namespace.
808
809 - What if the factory model doesn't work for me?
810
811 See "License" below. Note also that one can export plain functions as well.
812
813 - Why do I always die with "invalid property type -3621" (or other garbage)?
814
815 You are passing an object with the wrong C type to `v8plus_obj()`. Like
816 all varargs functions, it cannot tell the correct size or type of the
817 objects you have passed it; they must match the preceding type argument or
818 it will not work correctly. In this particular case, you've most likely
819 done something like:
820
821 int foo = 0xdead;
822
823 v8plus_obj(V8PLUS_TYPE_NUMBER, "foo", foo, V8PLUS_TYPE_NONE);
824
825 An 'int' is 4 bytes in size, and the compiler reserves 4 bytes on the stack
826 and sticks the value of foo there. When `v8plus_obj` goes to read it, it
827 sees that the type is V8PLUS_TYPE_NUMBER, casts the address of the next
828 argument slot to a `double *`, and dereferences it, then moves the argument
829 list pointer ahead by the size of a double. Unfortunately, a double
830 is usually 8 bytes long, meaning that (a) the value of the property is going
831 to be comprised of the integer-encoded foo appended to the next data type,
832 and (b) the next data type is going to be read from either undefined memory
833 or from part of the address of the name of the next property. To cure this,
834 always make sure that you cast your integral arguments properly when using
835 V8PLUS_TYPE_NUMBER:
836
837 v8plus_obj(V8PLUS_TYPE_NUMBER, "foo", (double)foo, V8PLUS_TYPE_NONE);
838
839 ## License
840
841 MIT.
842
843 ## Bugs
844
845 See <https://github.com/wesolows/v8plus/issues>.
846
847 ## Consumers
848
849 This is an incomplete list of native addons known to be using v8+. If your
850 addon uses v8+, please let me know and I will include it here.
851
852 - <https://github.com/wesolows/node-contract>