1 { 2 "author": { 3 "name": "Keith M Wesolowski", 4 "email": "keith.wesolowski@joyent.com" 5 }, 6 "name": "v8plus", 7 "description": "utility environment for writing addons in C", 8 "version": "0.1.0", 9 "contributors": [ 10 { 11 "name": "Joshua M. Clulow", 12 "email": "jmc@joyent.com" 13 } 14 ], 15 "repository": { 16 "type": "git", 17 "url": "git://github.com/joyent/v8plus.git" 18 }, 19 "bugs": { 20 "url": "http://github.com/joyent/v8plus/issues" 21 }, 22 "dependencies": { 23 "posix-getopt": "~0.0.1" 24 }, 25 "main": "origin.js", 26 "readme": "# v8+: Node.js addon C++ to C boundary layer\n\nThis layer offers a way to write at least simple Node.js addons in C without\nall the horrible C++ goop you'd otherwise be expected to use. That goop\nstill exists, but you don't have to write it. More importantly, you can\nwrite your module in a sane programming environment, avoiding the confusing\nand error-prone C++ semantics.\n\n## Usage\n\nUnlike most Node.js modules, v8+ does nothing by itself. It is intended to\nbe used as a build-time dependency of your native addon, providing you with\nan alternate programming environment.\n\nFor full docs, read the source code.\n\n## Node.js Support\n\nv8+ works with, and has been tested to some extent with, Node.js 0.6.18 and\n0.8.1. It most likely works with other micro versions in the 0.6 and 0.8\nseries as well. Note that this does not mean you can necessarily expect an\naddon built against a particular minor release of Node.js to work with any\nother minor release of Node.js.\n\n## Building and Installing\n\nThe v8+ source code is compiled into your module directly along with your\ncode. There is no separate v8+ library or node module, so the v8+ source,\ntools, and makefiles are required to be present at the time your module is\nbuilt. They are not required at runtime.\n\nNormally, your addon module will depend on the v8plus package and install it\nusing npm. The v8+ makefiles are set up to accommodate the installation of\nv8+ anywhere `node(1)` would be able to find it using `require()` if it were\na normal JavaScript module, so simply including it as a dependency in your\n`package.json` will work correctly. In addition, you will need to create a\n(normally trivial) makefile for your module that includes the makefiles\ndistributed as part of v8+. Once you have done so, it is sufficient to run\n`gmake` to generate the native loadable module used by Node.js.\n\nThe overall outline for creating a v8+ module looks something like this:\n\n1. Write the C code that does whatever your module does. Be sure to\n\\#include \"v8plus_glue.h\". Do not include any other v8+ headers.\n\n2. Create an appropriate `package.json` file. See below for details.\n\n3. Create a skeleton makefile. See below for details.\n\n4. Create a JSON file defining the error codes your module will use. See\nErrors below.\n\nYou should not (and need not) modify either of the delivered makefiles;\noverride the definitions in Makefile.v8plus.defs in your makefile as\nappropriate.\n\n### Packaging Considerations\n\nThere are two essential properties your `package.json` must contain in order\nto use v8+ with npm:\n\n1. A dependency on `v8plus`.\n\n2. An appropriate script entry for building your module. It is strongly\n recommended that you use something like the following:\n\n \"postinstall\": \"gmake $(eval echo ${MAKE_OVERRIDES})\"\n\nThis will allow someone building your module to set make variables by adding\nthem to the `MAKE_OVERRIDES` environment variable; e.g.,\n\n $ MAKE_OVERRIDES=\"CTFCONVERT=/bin/true CTFMERGE=/bin/true\" npm install\n\n### Tying into the Makefiles\n\nThe makefiles shipped with v8+ do the great majority of the heavy lifting\nfor you. A minimally functional makefile for your addon must contain four\nthings:\n\n1. Variable definitions for `V8PLUS` and `PREFIX_NODE`. Alternately, you\n may choose to provide these on the command line or via the environment.\n It is recommended that these assignments be made exactly as follows,\n which will cause the addon to be built against the `node` that is found\n first in your path:\n\n PREFIX_NODE := $(shell dirname `bash -c 'hash node; hash -t node'`)/..\n V8PLUS := $(shell $(PREFIX_NODE)/bin/node -e 'require(\"v8plus\");')\n\n Note that the mechanism for finding `node` will not work correctly if\n yours is a symlink. This invocation of node(1) uses a v8+ mechanism to\n locate v8+ sources anywhere that node(1) can find them and should not be\n modified unless you want to test an alternate v8+.\n\n2. The exact line:\n\n include $(V8PLUS)/Makefile.v8plus.defs\n\n3. Variable assignments specific to your module. In particular, you must\n define `SRCS`, `MODULE`, and `ERRNO_JSON`. Additional customisation is\n optional.\n\n4. The exact line:\n\n include $(V8PLUS)/Makefile.v8plus.targ\n\nAdditional arbitrary customisation is possible using standard makefile\nsyntax; most things that are useful to change already have variables defined\nin `Makefile.v8plus.defs` whose values you may append to or override. For\nexample, you may cause additional system libraries to be linked in by\nappending `-lname` to the `LIBS` variable. By default, the makefiles assume\nthat your sources are located in the `src` subdirectory of your module, and\nthat you want the sole output of the build process to be called\n`$(MODULE).node` and located in the `lib` subdirectory. This can be changed\nby overriding the `MODULE_DIR` variable.\n\nA simple example makefile may be found in the `examples/` subdirectory, and\nadditional examples may be found in existing consumers; see Consumers below.\nThe GNU people also provide a good manual for make if you get really stuck;\nsee <http://www.gnu.org/software/make/manual/make.html>. In general,\nwriting the necessary makefile fragment is expected to be as easy as or\neasier than the equivalent task using `node-waf` or `node-gyp`, so if you're\nfinding it unexpectedly difficult or complicated there's probably an easier\nway.\n\nThe makefiles follow GNU make syntax; other makes may not work but patches\nthat correct this are generally welcome (in particular, Sun make and GNU\nmake have different and incompatible ways to set a variable from the output\nof a shell command, and there is no way I know to accommodate both).\n\n### Binary Interface\n\nBy default, the resulting object is linked with the `-zdefs` option, which\nwill cause the build to fail if any unresolved symbols remain. In order to\naccommodate this, a mapfile specifying the available global symbols in your\n`node` binary is automatically generated as part of the build process. This\nmakes it much easier to debug missing libraries; otherwise, a module with\nunresolved symbols will fail to load at runtime with no useful explanation.\nMapfile generation probably works only on illumos-derived systems. Patches\nthat add support for other linkers are welcome.\n\nYour module will have all symbols (other than `init`, which is used directly\nby Node.js) reduced to local visibility, which is strongly recommended. If\nfor some reason you want your module's symbols to be visible to Node.js or\nto other modules, you will have to modify the script that generates the\nmapfile. See the `$(MAPFILE)` target in `Makefile.v8plus.targ`.\n\n## API\n\nYour module is an object factory that instantiates and returns native\nobjects, to which a fixed set of methods is attached as properties. The\nconstructor, destructor, and methods all correspond 1-1 with C functions.\nIn addition, you may create additional class methods associated with the\nnative module itself, each of which will also have a 1-1 relationship to a\nset of C functions.\n\nThis functionality is generally sufficient to interface with the system in\nuseful ways, but it is by no means exhaustive. Architectural limitations\nare noted throughout the documentation.\n\nSubsequent sections describe the API in greater detail, along with most of\nthe C functions that v8+ provides. Some utility functions may not be listed\nhere; see `v8plus_glue.h` for additional commentary and functions that are\navailable to you.\n\n### Constructors, Methods, and Functions\n\nThe interface between your module and v8+ consists of a handful of objects\nwith fixed types and names. These are:\n\n\tconst v8plus_c_ctor_f v8plus_ctor = my_ctor;\n\tconst v8plus_c_dtor_f v8plus_dtor = my_dtor;\n\tconst char *v8plus_js_factory_name = \"_new\";\n\tconst char *v8plus_js_class_name = \"MyObjectBinding\";\n\tconst v8plus_method_descr_t v8plus_methods[] = {\n\t {\n\t md_name: \"_my_method\",\n\t md_c_func: my_method\n\t },\n\t\t...\n\t};\n\tconst uint_t v8plus_method_count =\n\t sizeof (v8plus_methods) / sizeof (v8plus_methods[0]);\n\n\tconst v8plus_static_descr_t v8plus_static_methods[] = {\n\t {\n\t sd_name: \"_my_function\",\n\t sd_c_func: my_function\n\t },\n\t\t...\n\t};\n\tconst uint_t v8plus_static_method_count =\n\t sizeof (v8plus_static_methods) / sizeof (v8plus_static_methods[0]);\n\nAll of these must be present even if they have zero length or are NULL. The\nprototypes and semantics of each function type are as follows:\n\n### nvlist_t *v8plus_c_ctor_f(const nvlist_t *ap, void **opp)\n\nThe constructor is responsible for creating the C object corresponding to\nthe native JavaScript object being created. It is not a true constructor in\nthat you are actually an object factory; the C++ function associated with\nthe JavaScript constructor is called for you. Your encoded arguments are in\n`ap`. Allocate and populate a C object, stuff it into `*opp`, and return\n`v8plus_void()`. If you need to throw an exception you can do so by\nreturning `v8plus_error()` or one of its wrappers, or by setting\n`_v8plus_errno` using one of those functions and then returning an nvlist\nwith an `err` member representing a decorated exception.\n\n### void v8plus_c_dtor_f(void *op)\n\nFree the C object `op` and anything else associated with it. Your object is\ngoing away. This function may be empty if the constructor did not allocate\nany memory (i.e., `op` is not a pointer to dynamically allocated memory).\n\n### nvlist_t *v8plus_c_method_f(void *op, const nvlist_t *ap)\n\nWhen the JavaScript method is called in the context of your object, the\ncorresponding C function is invoked. `op` is the C object associated with\nthe JavaScript object, and `ap` is the encoded list of arguments to the\nfunction. Return an encoded object with a `res` member, or use one of the\nerror/exception patterns.\n\n### nvlist_t *v8plus_c_static_method_f(const nvlist_t *ap)\n\nIn addition to methods on the native objects returned by your constructor,\nyou can also provide a set of functions on the native binding object itself.\nThis may be useful for providing bindings to libraries for which no object\nrepresentation makes sense, or that have functions that operate outside the\ncontext of any particular object. Your arguments are once again encoded in\n`ap`, and your return values are an object containing `res` or an error.\n\n### Argument Handling\n\nWhen JavaScript objects cross the boundary from C++ to C, they are converted\nfrom v8 C++ objects into C nvlists. This means that they are effectively\npassed by value, unlike in JavaScript or in native addons written in C++.\nThe arguments to the JavaScript function are treated as an array and\nmarshalled into a single nvlist whose properties are named \"0\", \"1\", and so\non. Each such property is encoded as follows:\n\n- numbers and Number objects (regardless of size): double\n- strings and String objects: UTF-8 encoded C string\n- booleans and Boolean objects: boolean_value\n- undefined: boolean\n- null: byte, value 0\n- Objects, including Arrays: nvlist with own properties as members and the\nmember \".__v8plus_type\" set to the object's JavaScript type name. Note\nthat the member name itself begins with a . to reduce the likelihood of a\ncollision with an actual JavaScript member name.\n- JavaScript Functions are passed in a format suitable for use with\n `nvlist_lookup_jsfunc()` and `v8plus_args()` with the V8PLUS_TYPE_JSFUNC\n token. This type is restricted; see below.\n\nBecause JavaScript arrays may be sparse, we cannot use the libnvpair array\ntypes. Consider them reserved for internal use. JavaScript Arrays are\nrepresented as they really are in JavaScript: objects with properties whose\nnames happen to be integers.\n\nOther data types cannot be represented and will result in a TypeError\nbeing thrown. If your object has methods that need other argument types,\nyou cannot use v8+.\n\nSide effects within the VM, including modification of the arguments, are\nnot supported. If you need them, you cannot use v8+.\n\nWhile the standard libnvpair functions may be used to inspect the arguments\nto a method or function, v8+ also provides the `v8plus_args()` and\n`v8plus_typeof()` convenience functions, which simplify checking the types\nand obtaining the values of arguments.\n\n### int v8plus_args(const nvlist_t *lp, uint_t flags, v8plus_type_t t, ...)\n\nThis function checks `lp` for the exact sequence of arguments specified by\nthe list of types provided in the parameter list. If `V8PLUS_ARG_F_NOEXTRA`\nis set in `flags`, the list of arguments must match exactly, with no\nadditional arguments. The parameter list must be terminated by\n`V8PLUS_TYPE_NONE`.\n\nFollowing `flags` is a list of argument data types and, for most data types,\npointers to locations at which the native C value of that argument should be\nstored. The following JavaScript argument data types are supported; for\neach, the parameter immediately following the data type parameter must be of\nthe indicated C type. This parameter may be `NULL`, in which case the value\nwill not be stored anywhere.\n\n- V8PLUS_TYPE_NONE: used to terminate the parameter list only\n- V8PLUS_TYPE_STRING: char **\n- V8PLUS_TYPE_NUMBER: double *\n- V8PLUS_TYPE_BOOLEAN: boolean_t *\n- V8PLUS_TYPE_JSFUNC: v8plus_jsfunc_t *\n- V8PLUS_TYPE_OBJECT: nvlist_t **\n- V8PLUS_TYPE_NULL: no parameter\n- V8PLUS_TYPE_UNDEFINED: no parameter\n- V8PLUS_TYPE_INVALID: data_type_t (see below)\n- V8PLUS_TYPE_ANY: nvpair_t **\n- V8PLUS_TYPE_STRNUMBER64: uint64_t *\n- V8PLUS_TYPE_INL_OBJECT: illegal\n\nIn most cases, the behaviour is straightforward: the value pointer parameter\nprovides a location into which the C value of the specified argument should\nbe stored. If the entire argument list matches the template, each\nargument's C value is stored in its respective location. If not, no values\nare stored, in the return value locations, `_v8plus_errno` is set\nappropriately, and -1 is returned.\n\nThree data types warrant further explanation: an argument of type\n`V8PLUS_TYPE_INVALID` is any argument that may or may not match one of the\nacceptable types. Its nvpair data type tag is stored and the argument\ntreated as matching. The value is ignored. `V8PLUS_TYPE_STRNUMBER64` is\nused with strings that should be interpreted as 64-bit unsigned integers.\nIf the argument is not a string, or is not parseable as a 64-bit unsigned\ninteger, the argument will be treated as a mismatch. Finally,\n`V8PLUS_TYPE_INL_OBJECT` is not supported with `v8plus_args()`; JavaScript\nobjects in the argument list must be individually inspected as nvlists.\n\nA simple example:\n\n\tdouble_t d;\n\tboolean_t b;\n\tchar *s;\n\tv8plus_jsfunc_t f;\n\n\t/*\n\t * This function requires exactly four arguments: a number, a\n\t * boolean, a string, and a callback function. It is not acceptable\n\t * to pass superfluous arguments to it.\n\t */\n\tif (v8plus_args(ap, V8PLUS_ARG_F_NOEXTRA,\n\t V8PLUS_TYPE_NUMBER, &d,\n\t V8PLUS_TYPE_BOOLEAN, &b,\n\t V8PLUS_TYPE_STRING, &s,\n\t V8PLUS_TYPE_JSFUNC, &f,\n\t V8PLUS_TYPE_NONE) != 0)\n\t\treturn (NULL);\n\n### v8plus_type_t v8plus_typeof(const nvpair_t *pp)\n\nThis function simply returns the v8+ data type corresponding to the\nname/value pair `pp`. If the value's type does not match the v8+ encoding\nrules, `V8PLUS_TYPE_INVALID` is returned. This function cannot fail and\ndoes not modify `_v8plus_errno`.\n\n### Returning Values\n\nSimilarly, when returning data across the boundary from C to C++, a\npointer to an nvlist must be returned. This object will be decoded in\nthe same manner as described above and returned to the JavaScript caller\nof your method. Note that booleans, strings, and numbers will be encoded\nas their primitive types, not objects. If you need to return something\ncontaining these object types, you cannot use v8+. Other data types\ncannot be represented. If you need to return them, you cannot use v8+.\n\nThe nvlist being returned must have one of two members: \"res\", an nvpair\ncontaining the result of the call to be returned, or \"err\", an nvlist\ncontaining members to be added to an exception. You may return a value of\nany decodable type, and likewise may decorate an exception with properties\nof any decodable type.\n\nFor convenience, you may return v8plus_void() instead of an nvlist,\nwhich indicates successful execution of a function that returns nothing.\n\nIn addition, the `v8plus_obj()` routine is available for instantiating\nJavaScript objects to return.\n\n### nvlist_t *v8plus_void(void)\n\nThis function clears `_v8plus_errno` and returns NULL. This is used to\nindicate to internal v8+ code that the method or function should not return\na value.\n\n### nvlist_t *v8plus_obj(v8plus_type_t t, ...)\n\nThis function creates and populates an nvlist conforming to the encoding\nrules of v8+ for returning a value or creating an exception. It can be used\nto create anything from a single encoded value to arbitrarily nested\nobjects. It is essentially the inverse of `v8plus_args()` above, with a few\ndifferences:\n\n- It cannot be used to encode invalid or illegal data types.\n- It accepts native C values, not pointers to them.\n- Each value must be named.\n- It can be used to encode nested objects inline using\n `V8PLUS_TYPE_INL_OBJECT`, followed by type, name, value triples,\n terminated with `V8PLUS_TYPE_NONE`.\n\nThis function can fail due to out-of-memory conditions, invalid or\nunsupported data types, or, most commonly, programmer error in casting the\narguments to the correct type. *It is extremely important that data values,\nparticularly integers, be cast to the appropriate type (double) when passed\ninto this function!*\n\nFollowing is a list of types and the C data types corresponding to their\nvalues:\n\n- V8PLUS_TYPE_NONE: used to terminate the parameter list only\n- V8PLUS_TYPE_STRING: char *\n- V8PLUS_TYPE_NUMBER: double\n- V8PLUS_TYPE_BOOLEAN: boolean_t\n- V8PLUS_TYPE_JSFUNC: v8plus_jsfunc_t\n- V8PLUS_TYPE_OBJECT: nvlist_t *\n- V8PLUS_TYPE_NULL: no parameter\n- V8PLUS_TYPE_UNDEFINED: no parameter\n- V8PLUS_TYPE_ANY: nvpair_t *\n- V8PLUS_TYPE_STRNUMBER64: uint64_t\n- V8PLUS_TYPE_INL_OBJECT: NONE-terminated type/value list\n\nA simple example, in which we return a JavaScript object with two members,\none number and one embedded object with a 64-bit integer property. Note\nthat if this function fails, we will return `NULL` with `_v8plus_errno` set\nappropriately, so v8+ will generate and throw an appropriate exception.\n\n\tint x;\n\tconst char *s;\n\n\t...\n\treturn (v8plus_obj(\n\t V8PLUS_TYPE_INL_OBJECT, \"res\",\n\t\tV8PLUS_TYPE_NUMBER, \"value\", (double)x,\n\t\tV8PLUS_TYPE_INL_OBJECT, \"detail\",\n\t\t V8PLUS_TYPE_STRNUMBER64, \"value64\", s,\n\t\t V8PLUS_TYPE_NONE,\n\t\tV8PLUS_TYPE_NONE,\n\t V8PLUS_TYPE_NONE));\n\nThe JSON representation of this object would be:\n\n\t{\n\t\t\"res\": {\n\t\t\t\"value\": <x>,\n\t\t\t\"detail\": {\n\t\t\t\t\"value64\": \"<s>\"\n\t\t\t}\n\t\t}\n\t}\n\n### v8plus_obj_setprops(nvlist_t *lp, v8plus_type_t t, ...)\n\nYou can also add or replace the values of properties in an existing nvlist,\nwhether created using `nvlist_alloc()` directly or via `v8plus_obj()`. The\neffect is very similar to `nvlist_merge()`, where the second list is created\non the fly from your argument list. The interpretation of the argument list\nis the same as for `v8plus_obj()`, and the two functions are implemented\nusing the same logic.\n\n### Exceptions\n\nIf you are unable to create an nvlist to hold exception data, or you want a\ngeneric exception to be thrown, return the value returned by v8plus_error().\nIn this case, the error code will be translated to an exception type and the\nmessage string will be used as the message member of the exception. Other\nmembers will not be present in the exception unless you also return an\nnvlist containing an 'err' member (or, from a constructor, any nvlist) Only\nbasic v8-provided exception types can be thrown; if your addon needs to\nthrow some other kind of exception, you will need to either use v8 directly\nor catch and re-throw from a JavaScript wrapper.\n\n## Errors\n\nThe v8plus_errno_t enumerated type and a family of utility functions are\nautomatically generated by generrno.js from a simple JSON file. The schema\nof this file is as follows:\n\n\t{\n\t\t\"error_base\": <string>,\n\t\t\"errors\": [\n\t\t{\n\t\t\t\"code\": <string>,\n\t\t\t\"msg\": <string>,\n\t\t\t\"exception\": <string>\n\t\t},\n\t\t... ]\n\t}\n\nFor each entry in the errors array, an identifier V8PLUSERR_code will be\nadded to v8plus_errno_t. By convention, code should be all upper case. The\ndefault error message (present in JavaScript exceptions if a more specific\nerror message is not provided to v8plus_error()) is given by the msg\nproperty. The exception property must be one of \"Error\", \"TypeError\",\n\"ReferenceError\", \"RangeError\", or \"SyntaxError\"; i.e., the standard\nexception types available in v8. This is the type of exception that will be\ngenerated and thrown when a C function returns NULL with this error code\nset. In addition, the built-in error codes V8PLUSERR_NOMEM,\nV8PLUSERR_YOUSUCK, and V8PLUSERR_UNKNOWN are available for your use,\nindicating an out of memory condition, programmer error (e.g., failure of\nsomething you would assert in JavaScript), and an error code that cannot be\ntranslated, respectively.\n\nSet the make variable ERRNO_JSON to the name of this file.\n\nTo set the value of `_v8plus_errno`, use one of the following functions. It\nis a bug to manipulate this variable directly.\n\n### nvlist_t *v8plus_verror(v8plus_errno_t e, const char *fmt, va_list)\n\nThis is the varargs analogue to `v8plus_error()` and has identical\nsemantics. Use this if you want to wrap manipulation of the v8+ error state\nwithin your own varargs functions.\n\n### nvlist_t *v8plus_error(v8plus_errno_t e, const char *fmt, ...)\n\nThis function sets the value of `_v8plus_errno` to `e` and sets the\nassociated error message string to the formatted string `fmt` using the\nargument list that follows. The format string and arguments are interpreted\nas by `vsnprintf(3c)`. NULL is returned, suitable for returning directly\nfrom a C function that provides a method if no exception decoration is\nrequired.\n\nIf `fmt` is NULL, a generic default message is used; for consumer-defined\nerror codes, that message is the one provided in `errno.json`.\n\n### nvlist_t *v8plus_nverr(int errno, const char *propname)\n\nThis function sets the value of `_v8plus_errno` to a value mapped from the\nsystem error code `errno` and sets the error message to a non-localised\nexplanation of the problem. The string `propname`, if non-NULL, is\nindicated in the message as the name of the nvlist property being\nmanipulated when the error occurred. NULL is returned.\n\n### nvlist_t *v8plus_syserr(int errno, const char *fmt, ...)\n\nAnalogous to `v8plus_error()`, this function instead sets the error code to\na mapped value derived from the system error code `errno`. Not all error\ncodes can be mapped; those that are not known are mapped onto\n`V8PLUSERR_UNKNOWN`. This function's semantics are otherwise identical to\nthose of `v8plus_error()`.\n\n### void v8plus_panic(const char *fmt, ...) __NORETURN\n\nThis function indicates a fatal runtime error. The format string `fmt` and\nsubsequent arguments are interpreted as by `vsnprintf(3c)` and written to\nstandard error, which is then flushed. `abort(3c)` or similar is then\ninvoked to terminate the Node.js process in which the addon is running. Use\nof this function should be limited to those circumstances in which an\ninternal inconsistency has been detected that renders further progress\nhazardous to user data or impossible.\n\n### Asynchrony\n\nThere are two main types of asynchrony supported by v8+. The first is the\ndeferred work model (using `uv_queue_work()` or the deprecated\n`eio_custom()` mechanisms) frequently written about and demonstrated by\nvarious practitioners around the world. In this model, your method or\nfunction takes a callback argument and returns immediately after enqueuing a\ntask to run on one of the threads in the Node.js worker thread pool. That\ntask consists of a C function to be run on the worker thread, which may not\nuse any V8 (or v8+) state, and a function to be run in the main event loop\nthread when that task has completed. The latter function is normally\nexpected to invoke the caller's original callback. In v8+, this takes the\nfollowing form:\n\n\tvoid *\n\tasync_worker(void *cop, void *ctxp)\n\t{\n\t\tmy_object_t *op = cop;\n\t\tmy_context_t *cp = ctxp;\n\t\tmy_result_t *rp = ...;\n\n\t\t/*\n\t\t * In thread pool context -- do not call any of the\n\t\t * following functions:\n\t\t * v8plus_obj_hold()\n\t\t * v8plus_obj_rele_direct()\n\t\t * v8plus_jsfunc_hold()\n\t\t * v8plus_jsfunc_rele_direct()\n\t\t * v8plus_call_direct()\n\t\t * v8plus_method_call_direct()\n\t\t * v8plus_defer()\n\t\t *\n\t\t * If you touch anything inside op, you may need locking to\n\t\t * protect against functions called in the main thread.\n\t\t */\n\t\t...\n\n\t\treturn (rp);\n\t}\n\n\tvoid\n\tasync_completion(void *cop, void *ctxp, void *resp)\n\t{\n\t\tmy_object_t *op = cop;\n\t\tmy_context_t *cp = ctxp;\n\t\tmy_result_t *rp = resp;\n\t\tnvlist_t *cbap;\n\t\tnvlist_t *cbrp;\n\n\t\t...\n\t\tcbap = v8plus_obj(\n\t\t V8PLUS_TYPE_WHATEVER, \"0\", rp->mr_value,\n\t\t V8PLUS_TYPE_NONE);\n\n\t\tif (cbap != NULL) {\n\t\t\tcbrp = v8plus_call(cp->mc_callback, cbap);\n\t\t\tnvlist_free(cbap);\n\t\t\tnvlist_free(cbrp);\n\t\t}\n\n\t\tv8plus_jsfunc_rele(cp->mc_callback);\n\t\tfree(cp);\n\t\tfree(rp);\n\t}\n\n\tnvlist_t *\n\tasync(void *cop, const nvlist_t *ap)\n\t{\n\t\tmy_object_t *op = cop;\n\t\tv8plus_jsfunc_t cb;\n\t\tmy_context_t *cp = malloc(sizeof (my_context_t));\n\t\t...\n\t\tif (v8plus_args(ap, 0, V8PLUS_TYPE_JSFUNC, &cb,\n\t\t V8PLUS_TYPE_NONE) != 0) {\n\t\t\tfree(cp);\n\t\t\treturn (NULL);\n\t\t}\n\n\t\tv8plus_jsfunc_hold(cb);\n\t\tcp->mc_callback = cb;\n\t\tv8plus_defer(op, cp, async_worker, async_completion);\n\n\t\treturn (v8plus_void());\n\t}\n\nThis mechanism uses `uv_queue_work()` and as such will tie up one of the\nworker threads in the pool for as long as `async_worker` is running.\n\nThe other asynchronous mechanism is the Node.js `EventEmitter` model. This\nmodel requires some assistance from JavaScript code, because v8+ native\nobjects do not inherit from `EventEmitter`. To make this work, you will\nneed to create a JavaScript object (the object your consumers actually use)\nthat inherits from `EventEmitter`, hang your native object off this object,\nand populate the native object with an appropriate method that will cause\nthe JavaScript object to emit events when the native object invokes that\nmethod. A simple example might look like this:\n\n\tvar util = require('util');\n\tvar binding = require('./native_binding');\n\tvar events = require('events');\n\n\tfunction\n\tMyObjectWrapper()\n\t{\n\t\tvar self = this;\n\n\t\tevents.EventEmitter.call(this);\n\t\tthis._native = binding._create.apply(this,\n\t\t Array.prototype.slice.call(arguments));\n\t\tthis._native._emit = function () {\n\t\t\tvar args = Array.prototype.slice.call(arguments);\n\t\t\tself.emit.apply(self, args);\n\t\t};\n\t}\n\tutil.inherits(MyObjectWrapper, events.EventEmitter);\n\nThen, in C code, you must arrange for libuv to call a C function in the\ncontext of the main event loop. The function `v8plus_method_call()` is safe\nto call from any thread: depending on the context in which it is invoked, it\nwill either make the call directly or queue the call in the main event loop\nand block on a reply. Simply arrange to call back into your JavaScript\nobject when you wish to post an event:\n\n\tnvlist_t *eap;\n\tnvlist_t *erp;\n\tmy_object_t *op = ...;\n\t...\n\teap = v8plus_obj(\n\t V8PLUS_TYPE_STRING, \"0\", \"my_event\",\n\t ...,\n\t V8PLUS_TYPE_NONE);\n\n\tif (eap != NULL) {\n\t\terp = v8plus_method_call(op, \"_emit\", eap);\n\t\tnvlist_free(eap);\n\t\tnvlist_free(erp);\n\t}\n\nThis example will generate an event named \"my_event\" and propagate it to\nlisteners registered with the `MyObjectWrapper` instance. If additional\narguments are associated with the event, they may be added to `eap` and will\nalso be passed along to listeners as arguments to their callbacks.\n\n### void v8plus_obj_hold(const void *op)\n\nPlaces a hold on the V8 representation of the specified C object. This is\nrarely necessary; `v8plus_defer()` performs this action for you, but other\nasynchronous mechanisms may require it. If you are returning from a method\ncall but have stashed a reference to the object somewhere and are not\ncalling `v8plus_defer()`, you must call this first. Holds and releases must\nbe balanced. Use of the object within a thread after releasing is a bug.\n\n### void v8plus_obj_rele(const void *op)\n\nReleases a hold placed by `v8plus_obj_hold()`. This function may be called\nsafely from any thread; releases from threads other than the main event loop\nare non-blocking and will occur some time in the future.\n\n### void v8plus_jsfunc_hold(v8plus_jsfunc_t f)\n\nPlaces a hold on the V8 representation of the specified JavaScript function.\nThis is required when returning from a C function that has stashed a\nreference to the function, typically to use it asynchronously as a callback.\nAll holds must be balanced with a release. Because a single hold is placed\non such objects when passed to you in an argument list (and released for you\nwhen you return), it is legal to reference and even to invoke such a\nfunction without first placing an additional hold on it.\n\n### void v8plus_jsfunc_rele(v8plus_jsfunc_t f)\n\nReleases a hold placed by `v8plus_jsfunc_hold()`. This function may be called\nsafely from any thread; releases from threads other than the main event loop\nthread are non-blocking and will occur some time in the future.\n\n### void v8plus_defer(void *op, void *ctx, worker, completion)\n\nEnqueues work to be performed in the Node.js shared thread pool. The object\n`op` and context `ctx` are passed as arguments to `worker` executing in a\nthread from that pool. The same two arguments, along with the worker's\nreturn value, are passed to `completion` executing in the main event loop\nthread. See example above.\n\n### nvlist_t *v8plus_call(v8plus_jsfunc_t f, const nvlist_t *ap)\n\nCalls the JavaScript function referred to by `f` with encoded arguments\n`ap`. The return value is the encoded return value of the function. The\nargument and return value encoding match the encodings that are used by C\nfunctions that provide methods.\n\nAs JavaScript functions must be called from the event loop thread,\n`v8plus_call()` contains logic to determine whether we are in the\ncorrect context or not. If we are running on some other thread we will\nqueue the request and sleep, waiting for the event loop thread to make the\ncall. In the simple case, where we are already in the correct thread, we\nmake the call directly.\n\nNote that when passing JavaScript functions around as callbacks, you must use\nfirst use `v8plus_jsfunc_hold()` from within the main event loop thread. Once\nfinished with the function, you may pass it to `v8plus_jsfunc_rele()` from any\nthread to clean up.\n\n### nvlist_t *v8plus_method_call(void *op, const char *name, const nvlist_t *ap)\n\nCalls the method named by `name` in the native object `op` with encoded\nargument list `ap`. The method must exist and must be a JavaScript\nfunction. Such functions may be attached by JavaScript code as in the event\nemitter example above. The effects of using this function to call a native\nmethod are undefined.\n\nWhen called from threads other than the main event loop thread,\n`v8plus_method_call()` uses the same queue-and-block logic as described above\nin `v8plus_call()`.\n\n## FAQ\n\n- Why?\n\nBecause C++ is garbage. Writing good software is challenging enough without\ntrying to understand a bunch of implicit side effects or typing templated\nidentifiers that can't fit in 80 columns without falling afoul of the\nlanguage's ambiguous grammar. Don't get me started.\n\n- Why not use [FFI](https://github.com/rbranson/node-ffi)?\n\nFFI is really cool; it offers us the ability to use C libraries without\nwriting bindings at all. However, it also exposes a lot of C nastiness to\nJavaScript code, essentially placing the interface boundary in consuming\ncode itself. This pretty much breaks the JavaScript interface model --\nfor example, you can't really have a function that inspects the types of its\narguments -- and requires you to write an additional C library anyway if you\nwant or need to do something natively that's not quite what the C library\nalready does. Of course, one could use it to write \"bindings\" in JavaScript\nthat actually look like a JavaScript interface, which may end up being the\nbest answer, especially if those are autogenerated from CTF! In short, v8+\nand FFI are different approaches to the problem. Use whichever fits your\nneed, and note that they're not mutually exclusive, either.\n\n- What systems can I use this on?\n\n[illumos](http://illumos.org) distributions, or possibly other platforms\nwith a working libnvpair. I'm sorry if your system doesn't have it; it's\nopen source and pretty easy to port.\n\nThere is an OSX port; see [the ZFS port's\nimplementation](http://code.google.com/p/maczfs/source/browse/#git%2Fusr%2Fsrc%2Flib%2Flibnvpair).\nUnfortunately this port lacks the requisite support for floating-point data\n(DATA_TYPE_DOUBLE) but you could easily add that from the illumos sources.\n\n- What about node-waf and node-gyp?\n\nFuck python, fuck WAF, and fuck all the hipster douchebags for whom make is\ntoo hard, too old, or \"too Unixy\". Make is simple, easy to use, and\nextremely reliable. It was building big, important pieces of software when\nyour parents were young, and it Just Works. If you don't like using make\nhere, you probably don't want to use v8+ either, so just go away. Write\nyour CoffeeScript VM in something else, and gyp-scons-waf-rake your way to\nan Instagram retirement in Bali with all your hipster douchebag friends.\nJust don't bother me about it, because I don't care.\n\n- Why is Node failing in dlopen()?\n\nMost likely, your module has a typo or needs to be linked with a library.\nNormally, shared objects like Node addons should be linked with -zdefs so that\nthese problems are found at build time, but Node doesn't deliver a mapfile\nspecifying its API so you're left with a bunch of undefined symbols you just\nhave to hope are defined somewhere in your node process's address space. If\nthey aren't, you're boned. LD_DEBUG=all will help you find the missing\nsymbol(s).\n\nAs of 0.0.2, v8+ builds a mapfile for your node binary at the time you build\nyour addon. It does not attempt to restrict the visibility of any symbols,\nso you will not be warned if your addon is using private or deprecated\nfunctionality in V8 or Node.js. Your build will, however, fail if you've\nneglected to link in any required libraries, typo'd a symbol name, etc.\n\n- Why use the old init() instead of NODE_MODULE()?\n\nBecause NODE_MODULE() is a macro that can't be passed another macro as the\nname of your addon. Using it would therefore require the source to v8+ to\nbe generated at build time to match your module's name, which is\ninconvenient. There may be a way to work around this.\n\n- Why can't I see my exception's decorative properties in JavaScript?\n\nBe careful when decorating exceptions. There are several built-in hidden\nproperties; if you decorate the exception with a property with the same\nname, you will change the hidden property's value but it will still be\nhidden. This almost certainly is not what you want, so you should prefix\nthe decorative property names with something unique to your module to avoid\nstepping on V8's (or JavaScript's) property namespace.\n\n- What if the factory model doesn't work for me?\n\nSee \"License\" below. Note also that one can export plain functions as well.\n\n- Why do I always die with \"invalid property type -3621\" (or other garbage)?\n\nYou are passing an object with the wrong C type to `v8plus_obj()`. Like\nall varargs functions, it cannot tell the correct size or type of the\nobjects you have passed it; they must match the preceding type argument or\nit will not work correctly. In this particular case, you've most likely\ndone something like:\n\n\tint foo = 0xdead;\n\n\tv8plus_obj(V8PLUS_TYPE_NUMBER, \"foo\", foo, V8PLUS_TYPE_NONE);\n\nAn 'int' is 4 bytes in size, and the compiler reserves 4 bytes on the stack\nand sticks the value of foo there. When `v8plus_obj` goes to read it, it\nsees that the type is V8PLUS_TYPE_NUMBER, casts the address of the next\nargument slot to a `double *`, and dereferences it, then moves the argument\nlist pointer ahead by the size of a double. Unfortunately, a double\nis usually 8 bytes long, meaning that (a) the value of the property is going\nto be comprised of the integer-encoded foo appended to the next data type,\nand (b) the next data type is going to be read from either undefined memory\nor from part of the address of the name of the next property. To cure this,\nalways make sure that you cast your integral arguments properly when using\nV8PLUS_TYPE_NUMBER:\n\n\tv8plus_obj(V8PLUS_TYPE_NUMBER, \"foo\", (double)foo, V8PLUS_TYPE_NONE);\n\n## License\n\nMIT.\n\n## Bugs\n\nSee <https://github.com/joyent/v8plus/issues>.\n\n## Consumers\n\nThis is an incomplete list of native addons known to be using v8+. If your\naddon uses v8+, please let me know and I will include it here.\n\n- <https://github.com/joyent/node-contract>\n", 27 "readmeFilename": "README.md", 28 "_id": "v8plus@0.1.0", 29 "_from": "v8plus@~0.1.0" 30 }