1 /*
2 * Copyright (c) 2012 Joyent, Inc. All rights reserved.
3 */
4
5 #include <sys/types.h>
6 #include <stdarg.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <alloca.h>
10 #include <dlfcn.h>
11 #include <libnvpair.h>
12 #include <node.h>
13 #include <v8.h>
14 #include <unordered_map>
15 #include <string>
16 #include "v8plus_impl.h"
17
18 #define V8PLUS_OBJ_TYPE_MEMBER ".__v8plus_type"
19 #define V8_EXCEPTION_CTOR_FMT \
20 "_ZN2v89Exception%u%sENS_6HandleINS_6StringEEE"
21
22 typedef struct cb_hdl {
23 v8::Handle<v8::Function> ch_hdl;
24 uint_t ch_refs;
25 boolean_t ch_persist;
26 } cb_hdl_t;
27
28 static std::unordered_map<uint64_t, cb_hdl_t> cbhash;
29 static uint64_t cbnext;
30 static void (*__real_nvlist_free)(nvlist_t *);
31
32
33 static const char *
34 cstr(const v8::String::Utf8Value &v)
35 {
36 return (*v);
37 }
38
39 /*
40 * Convenience macros for adding stuff to an nvlist and returning on failure.
41 */
42 #define LA_U(_l, _n, _e) \
43 if (((_e) = nvlist_add_boolean((_l), (_n))) != 0) \
44 return (_e)
45
46 #define LA_N(_l, _n, _e) \
47 if (((_e) = nvlist_add_byte((_l), (_n), 0)) != 0) \
48 return (_e)
49
50 #define LA_V(_l, _t, _n, _v, _e) \
51 if (((_e) = nvlist_add_##_t((_l), (_n), (_v))) != 0) \
52 return (_e)
53
54 #define LA_VA(_l, _t, _n, _v, _c, _e) \
55 if (((_e) = nvlist_add_##_t##_array((_l), (_n), (_v), (_c))) != 0) \
56 return (_e)
57
58 /*
59 * Add an element named <name> to list <lp> with a transcoded value
60 * corresponding to <vh> if possible. Only primitive types, objects that are
61 * thin wrappers for primitive types, and objects containing members whose
62 * types are all any of the above can be transcoded.
63 *
64 * Booleans and their Object type are encoded as boolean_value.
65 * Numbers and their Object type are encoded as double.
66 * Strings and their Object type are encoded as C strings (and assumed UTF-8).
67 * Any Object (including an Array) is encoded as an nvlist whose elements
68 * are the Object's own properties.
69 * Null is encoded as a byte with value 0.
70 * Undefined is encoded as the valueless boolean.
71 *
72 * Returns EINVAL if any argument fails these tests, or any other error code
73 * that may be returned by nvlist_add_XXX(3nvpair).
74 */
75 static int
76 nvlist_add_v8_Value(nvlist_t *lp, const char *name,
77 const v8::Handle<v8::Value> &vh)
78 {
79 int err = 0;
80
81 if (vh->IsBoolean()) {
82 boolean_t vv = vh->BooleanValue() ? _B_TRUE : _B_FALSE;
83 LA_V(lp, boolean_value, name, vv, err);
84 } else if (vh->IsNumber()) {
85 double vv = vh->NumberValue();
86 LA_V(lp, double, name, vv, err);
87 } else if (vh->IsString()) {
88 v8::String::Utf8Value s(vh);
89 const char *vv = cstr(s);
90 LA_V(lp, string, name, vv, err);
91 } else if (vh->IsUndefined()) {
92 LA_U(lp, name, err);
93 } else if (vh->IsNull()) {
94 LA_N(lp, name, err);
95 } else if (vh->IsNumberObject()) {
96 double vv = vh->NumberValue();
97 LA_V(lp, double, name, vv, err);
98 } else if (vh->IsStringObject()) {
99 v8::String::Utf8Value s(vh);
100 const char *vv = cstr(s);
101 LA_V(lp, string, name, vv, err);
102 } else if (vh->IsBooleanObject()) {
103 boolean_t vv = vh->BooleanValue() ? _B_TRUE : _B_FALSE;
104 LA_V(lp, boolean_value, name, vv, err);
105 } else if (vh->IsFunction()) {
106 cb_hdl_t ch;
107
108 ch.ch_hdl = v8::Handle<v8::Function>::Cast(vh);
109 ch.ch_refs = 1;
110 ch.ch_persist = _B_FALSE;
111
112 while (cbhash.find(cbnext) != cbhash.end())
113 ++cbnext;
114 cbhash.insert(std::make_pair(cbnext, ch));
115
116 LA_VA(lp, string, V8PLUS_JSF_COOKIE, NULL, 0, err);
117 LA_VA(lp, uint64, name, &cbnext, 1, err);
118 } else if (vh->IsObject()) {
119 v8::Local<v8::Object> oh = vh->ToObject();
120 v8::Local<v8::Array> keys = oh->GetOwnPropertyNames();
121 v8::Local<v8::String> th = oh->GetConstructorName();
122 v8::String::Utf8Value tv(th);
123 const char *type = cstr(tv);
124 nvlist_t *vlp;
125 uint_t i;
126
127 if ((err = nvlist_alloc(&vlp, NV_UNIQUE_NAME, 0)) != 0)
128 return (err);
129
130 /* XXX this is vile; can we handle this generally? */
131 if (strcmp(type, "Object") != 0) {
132 if (strcmp(type, "Array") == 0) {
133 if ((err = nvlist_add_string(vlp,
134 V8PLUS_OBJ_TYPE_MEMBER, type)) != 0) {
135 nvlist_free(vlp);
136 return (err);
137 }
138 } else {
139 /*
140 * XXX This is (C) programmer error. Should
141 * we plumb up a way to throw here?
142 */
143 (void) v8plus_panic("can't handle %s", type);
144 }
145 }
146
147 for (i = 0; i < keys->Length(); i++) {
148 char knname[16];
149 v8::Local<v8::Value> mk;
150 v8::Local<v8::Value> mv;
151 const char *k;
152
153 (void) snprintf(knname, sizeof (knname), "%u", i);
154 mk = keys->Get(v8::String::New(knname));
155 mv = oh->Get(mk);
156 v8::String::Utf8Value mks(mk);
157 k = cstr(mks);
158
159 if ((err = nvlist_add_v8_Value(vlp, k, mv)) != 0) {
160 nvlist_free(vlp);
161 return (err);
162 }
163 }
164
165 LA_V(lp, nvlist, name, vlp, err);
166 } else {
167 return (EINVAL);
168 }
169
170 return (0);
171 }
172
173 #undef LA_U
174 #undef LA_N
175 #undef LA_V
176
177 nvlist_t *
178 v8plus::v8_Arguments_to_nvlist(const v8::Arguments &args)
179 {
180 char name[16];
181 nvlist_t *lp;
182 int err;
183 uint_t i;
184
185 if ((err = nvlist_alloc(&lp, NV_UNIQUE_NAME, 0)) != 0)
186 return (v8plus_nverr(err, NULL));
187
188 for (i = 0; i < (uint_t)args.Length(); i++) {
189 (void) snprintf(name, sizeof (name), "%u", i);
190 if ((err = nvlist_add_v8_Value(lp, name, args[i])) != 0) {
191 nvlist_free(lp);
192 return (v8plus_nverr(err, name));
193 }
194 }
195
196 return (lp);
197 }
198
199 static void
200 decorate_object(v8::Local<v8::Object> &oh, const nvlist_t *lp)
201 {
202 nvpair_t *pp = NULL;
203
204 while ((pp =
205 nvlist_next_nvpair(const_cast<nvlist_t *>(lp), pp)) != NULL) {
206 oh->Set(v8::String::New(nvpair_name(pp)),
207 v8plus::nvpair_to_v8_Value(pp));
208 }
209 }
210
211 #define RETURN_JS(_p, _jt, _ct, _xt, _pt) \
212 do { \
213 _ct _v; \
214 (void) nvpair_value_##_pt(const_cast<nvpair_t *>(_p), &_v); \
215 return (v8::_jt::New((_xt)_v)); \
216 } while (0)
217
218 v8::Handle<v8::Value>
219 v8plus::nvpair_to_v8_Value(const nvpair_t *pp)
220 {
221 const char *type;
222
223 switch (nvpair_type(const_cast<nvpair_t *>(pp))) {
224 case DATA_TYPE_BOOLEAN:
225 return (v8::Undefined());
226 case DATA_TYPE_BOOLEAN_VALUE:
227 RETURN_JS(pp, Boolean, boolean_t, bool, boolean_value);
228 case DATA_TYPE_BYTE:
229 {
230 uint8_t _v = (uint8_t)-1;
231
232 if (nvpair_value_byte(const_cast<nvpair_t *>(pp), &_v) != 0 ||
233 _v != 0) {
234 v8plus_panic("bad byte value %02x\n", _v);
235 }
236
237 return (v8::Null());
238 }
239 case DATA_TYPE_INT8:
240 RETURN_JS(pp, Number, int8_t, double, int8);
241 case DATA_TYPE_UINT8:
242 RETURN_JS(pp, Number, uint8_t, double, uint8);
243 case DATA_TYPE_INT16:
244 RETURN_JS(pp, Number, int16_t, double, int16);
245 case DATA_TYPE_UINT16:
246 RETURN_JS(pp, Number, uint16_t, double, uint16);
247 case DATA_TYPE_INT32:
248 RETURN_JS(pp, Number, int32_t, double, int32);
249 case DATA_TYPE_UINT32:
250 RETURN_JS(pp, Number, uint32_t, double, uint32);
251 case DATA_TYPE_INT64:
252 RETURN_JS(pp, Number, int64_t, double, int64);
253 case DATA_TYPE_UINT64:
254 RETURN_JS(pp, Number, uint64_t, double, uint64);
255 case DATA_TYPE_DOUBLE:
256 RETURN_JS(pp, Number, double, double, double);
257 case DATA_TYPE_STRING:
258 RETURN_JS(pp, String, char *, const char *, string);
259 case DATA_TYPE_UINT64_ARRAY:
260 {
261 std::unordered_map<uint64_t, cb_hdl_t>::iterator it;
262 uint64_t *vp;
263 uint_t nv;
264 int err;
265
266 if ((err = nvpair_value_uint64_array(const_cast<nvpair_t *>(pp),
267 &vp, &nv)) != 0)
268 v8plus_panic("bad JSFUNC pair: %s", strerror(err));
269 if (nv != 1)
270 v8plus_panic("bad uint64 array length %u", nv);
271 if ((it = cbhash.find(*vp)) == cbhash.end())
272 v8plus_panic("callback hash tag %llu not found", *vp);
273
274 return (it->second.ch_hdl);
275 }
276 case DATA_TYPE_NVLIST:
277 {
278 nvlist_t *lp;
279 v8::Local<v8::Object> oh;
280
281 (void) nvpair_value_nvlist(const_cast<nvpair_t *>(pp), &lp);
282
283 if (nvlist_lookup_string(const_cast<nvlist_t *>(lp),
284 V8PLUS_OBJ_TYPE_MEMBER, const_cast<char **>(&type)) != 0)
285 type = "Object";
286
287 if (strcmp(type, "Array") == 0)
288 oh = v8::Array::New()->ToObject();
289 else if (strcmp(type, "Object") != 0)
290 v8plus_panic("bad object type %s\n", type);
291 else
292 oh = v8::Object::New();
293
294 decorate_object(oh, lp);
295 return (oh);
296 }
297 default:
298 v8plus_panic("bad data type %d\n",
299 nvpair_type(const_cast<nvpair_t *>(pp)));
300 }
301
302 /*NOTREACHED*/
303 return (v8::Undefined());
304 }
305
306 #undef RETURN_JS
307
308 static uint_t
309 nvlist_length(const nvlist_t *lp)
310 {
311 uint_t l = 0;
312 nvpair_t *pp = NULL;
313
314 while ((pp =
315 nvlist_next_nvpair(const_cast<nvlist_t *>(lp), pp)) != NULL)
316 ++l;
317
318 return (l);
319 }
320
321 static void
322 nvlist_to_v8_argv(const nvlist_t *lp, int *argcp, v8::Handle<v8::Value> *argv)
323 {
324 nvpair_t *pp;
325 char name[16];
326 int i;
327
328 for (i = 0; i < *argcp; i++) {
329 (void) snprintf(name, sizeof (name), "%u", i);
330 if (nvlist_lookup_nvpair(const_cast<nvlist_t *>(lp),
331 name, &pp) != 0)
332 break;
333 argv[i] = v8plus::nvpair_to_v8_Value(pp);
334 }
335
336 *argcp = i;
337 }
338
339 static v8::Local<v8::Value>
340 sexception(const char *type, const nvlist_t *lp, const char *msg)
341 {
342 char *ctor_name;
343 v8::Local<v8::Value> (*excp_ctor)(v8::Handle<v8::String>);
344 void *obj_hdl;
345 size_t len;
346 v8::Local<v8::Value> excp;
347 v8::Local<v8::Object> obj;
348 v8::Local<v8::String> jsmsg = v8::String::New(msg);
349
350 if (type == NULL) {
351 type = v8plus_excptype(_v8plus_errno);
352 if (type == NULL)
353 type = "Error";
354 }
355
356 len = snprintf(NULL, 0, V8_EXCEPTION_CTOR_FMT,
357 (uint_t)strlen(type), type);
358 ctor_name = reinterpret_cast<char *>(alloca(len + 1));
359 (void) snprintf(ctor_name, len + 1, V8_EXCEPTION_CTOR_FMT,
360 (uint_t)strlen(type), type);
361
362 obj_hdl = dlopen(NULL, RTLD_NOLOAD);
363 if (obj_hdl == NULL)
364 v8plus_panic("%s\n", dlerror());
365
366 excp_ctor = (v8::Local<v8::Value>(*)(v8::Handle<v8::String>))(
367 dlsym(obj_hdl, ctor_name));
368
369 if (excp_ctor == NULL) {
370 (void) dlclose(obj_hdl);
371 if (strcmp(type, "Error") == 0) {
372 v8plus_panic("Unable to find %s, aborting\n",
373 ctor_name);
374 } else {
375 excp = v8::Exception::Error(v8::String::New(
376 "Nested exception: illegal exception type"));
377 return (excp);
378 }
379 }
380
381 excp = excp_ctor(jsmsg);
382 (void) dlclose(obj_hdl);
383
384 if (lp == NULL)
385 return (excp);
386
387 obj = excp->ToObject();
388 decorate_object(obj, lp);
389
390 return (excp);
391 }
392
393 v8::Local<v8::Value>
394 v8plus::exception(const char *type, const nvlist_t *lp, const char *fmt, ...)
395 {
396 v8::Local<v8::Value> exception;
397 char *msg;
398 size_t len;
399 va_list ap;
400
401 if (fmt != NULL) {
402 va_start(ap, fmt);
403 len = vsnprintf(NULL, 0, fmt, ap);
404 va_end(ap);
405 msg = reinterpret_cast<char *>(alloca(len + 1));
406
407 va_start(ap, fmt);
408 (void) vsnprintf(msg, len + 1, fmt, ap);
409 va_end(ap);
410 } else {
411 msg = _v8plus_errmsg;
412 }
413
414 exception = sexception(type, lp, msg);
415
416 return (exception);
417 }
418
419 extern "C" nvlist_t *
420 v8plus_call(v8plus_jsfunc_t f, const nvlist_t *lp)
421 {
422 std::unordered_map<uint64_t, cb_hdl_t>::iterator it;
423 const int max_argc = nvlist_length(lp);
424 int argc, err;
425 v8::Handle<v8::Value> argv[max_argc];
426 v8::Handle<v8::Value> res;
427 nvlist_t *rp;
428
429 if ((it = cbhash.find(f)) == cbhash.end())
430 v8plus_panic("callback hash tag %llu not found", f);
431
432 argc = max_argc;
433 nvlist_to_v8_argv(lp, &argc, argv);
434
435 if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0)
436 return (v8plus_nverr(err, NULL));
437
438 v8::TryCatch tc;
439 res = it->second.ch_hdl->Call(v8::Context::GetCurrent()->Global(),
440 argc, argv);
441 if (tc.HasCaught()) {
442 err = nvlist_add_v8_Value(rp, "err", tc.Exception());
443 tc.Reset();
444 if (err != 0) {
445 nvlist_free(rp);
446 return (v8plus_nverr(err, "err"));
447 }
448 } else if ((err = nvlist_add_v8_Value(rp, "res", res)) != 0) {
449 nvlist_free(rp);
450 return (v8plus_nverr(err, "res"));
451 }
452
453 return (rp);
454 }
455
456 extern "C" nvlist_t *
457 v8plus_method_call_direct(void *cop, const char *name, const nvlist_t *lp)
458 {
459 v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop);
460 const int max_argc = nvlist_length(lp);
461 int argc, err;
462 v8::Handle<v8::Value> argv[max_argc];
463 v8::Handle<v8::Value> res;
464 nvlist_t *rp;
465
466 if (v8plus::ObjectWrap::in_event_thread() != _B_TRUE)
467 v8plus_panic("direct method call outside of event loop");
468
469 argc = max_argc;
470 nvlist_to_v8_argv(lp, &argc, argv);
471
472 if ((err = nvlist_alloc(&rp, NV_UNIQUE_NAME, 0)) != 0)
473 return (v8plus_nverr(err, NULL));
474
475 v8::TryCatch tc;
476 res = op->call(name, argc, argv);
477 if (tc.HasCaught()) {
478 err = nvlist_add_v8_Value(rp, "err", tc.Exception());
479 tc.Reset();
480 if (err != 0) {
481 nvlist_free(rp);
482 return (v8plus_nverr(err, "err"));
483 }
484 } else if ((err = nvlist_add_v8_Value(rp, "res", res)) != 0) {
485 nvlist_free(rp);
486 return (v8plus_nverr(err, "res"));
487 }
488
489 return (rp);
490 }
491
492 extern "C" void
493 v8plus_async_callback(uv_async_t *async, __attribute__((unused)) int status)
494 {
495 if (v8plus::ObjectWrap::in_event_thread() != _B_TRUE)
496 v8plus_panic("async callback called outside of event loop");
497
498 for (;;) {
499 v8plus_async_call_t *ac;
500
501 if ((ac = v8plus::ObjectWrap::next_async_call()) == NULL)
502 break;
503
504 if (pthread_mutex_lock(&ac->ac_mtx) != 0)
505 v8plus_panic("could not lock async call mutex");
506
507 if (ac->ac_run == _B_TRUE)
508 v8plus_panic("async call already run");
509
510 ac->ac_return = v8plus_method_call_direct(ac->ac_cop,
511 ac->ac_name, ac->ac_lp);
512 ac->ac_run = _B_TRUE;
513
514 if (pthread_cond_broadcast(&ac->ac_cv) != 0)
515 v8plus_panic("could not signal async call condvar");
516 if (pthread_mutex_unlock(&ac->ac_mtx) != 0)
517 v8plus_panic("could not unlock async call mutex");
518 }
519 }
520
521 extern "C" nvlist_t *
522 v8plus_method_call(void *cop, const char *name, const nvlist_t *lp)
523 {
524 v8plus_async_call_t ac;
525
526 if (v8plus::ObjectWrap::in_event_thread() == _B_TRUE) {
527 /*
528 * We're running in the event loop thread, so we can make the
529 * call directly.
530 */
531 return (v8plus_method_call_direct(cop, name, lp));
532 }
533
534 /*
535 * As we cannot manipulate v8plus/V8/Node structures directly from
536 * outside the event loop thread, we push the call arguments onto a
537 * queue and post to the event loop thread. We then sleep on our
538 * condition variable until the event loop thread makes the call
539 * for us and wakes us up.
540 */
541 ac.ac_cop = cop;
542 ac.ac_name = name;
543 ac.ac_lp = lp;
544 if (pthread_mutex_init(&ac.ac_mtx, NULL) != 0)
545 v8plus_panic("could not init async call mutex");
546 if (pthread_cond_init(&ac.ac_cv, NULL) != 0)
547 v8plus_panic("could not init async call condvar");
548 ac.ac_run = _B_FALSE;
549 ac.ac_return = NULL;
550
551 v8plus::ObjectWrap::post_async_call(&ac);
552
553 if (pthread_mutex_lock(&ac.ac_mtx) != 0)
554 v8plus_panic("could not lock async call mutex");
555 while (ac.ac_run == _B_FALSE) {
556 if (pthread_cond_wait(&ac.ac_cv, &ac.ac_mtx) != 0)
557 v8plus_panic("could not wait on async call condvar");
558 }
559
560 return (ac.ac_return);
561 }
562
563 extern "C" int
564 nvlist_lookup_v8plus_jsfunc(const nvlist_t *lp, const char *name,
565 v8plus_jsfunc_t *vp)
566 {
567 uint64_t *lvp;
568 uint_t nv;
569 int err;
570
571 err = nvlist_lookup_uint64_array(const_cast<nvlist_t *>(lp),
572 name, &lvp, &nv);
573 if (err != 0)
574 return (err);
575
576 if (nv != 1)
577 v8plus_panic("bad array size %u for callback hash tag", nv);
578
579 *vp = *lvp;
580 return (0);
581 }
582
583 extern "C" void
584 v8plus_jsfunc_hold(v8plus_jsfunc_t f)
585 {
586 v8::Persistent<v8::Function> pfh;
587 std::unordered_map<uint64_t, cb_hdl_t>::iterator it;
588
589 if ((it = cbhash.find(f)) == cbhash.end())
590 v8plus_panic("callback hash tag %llu not found", f);
591
592 if (!it->second.ch_persist) {
593 pfh = v8::Persistent<v8::Function>::New(it->second.ch_hdl);
594 it->second.ch_hdl = pfh;
595 it->second.ch_persist = _B_TRUE;
596 }
597 ++it->second.ch_refs;
598 }
599
600 extern "C" void
601 v8plus_jsfunc_rele(v8plus_jsfunc_t f)
602 {
603 v8::Local<v8::Function> lfh;
604 std::unordered_map<uint64_t, cb_hdl_t>::iterator it;
605
606 if ((it = cbhash.find(f)) == cbhash.end())
607 v8plus_panic("callback hash tag %llu not found", f);
608
609 if (it->second.ch_refs == 0)
610 v8plus_panic("releasing unheld callback hash tag %llu", f);
611
612 if (--it->second.ch_refs == 0) {
613 if (it->second.ch_persist) {
614 v8::Persistent<v8::Function> pfh(it->second.ch_hdl);
615 pfh.Dispose();
616 }
617 cbhash.erase(it);
618 }
619 }
620
621 static size_t
622 library_name(const char *base, const char *version, char *buf, size_t len)
623 {
624 #ifdef __MACH__
625 return (snprintf(buf, len, "lib%s.%s%sdylib", base,
626 version ? version : "", version ? "." : ""));
627 #else
628 return (snprintf(buf, len, "lib%s.so%s%s", base,
629 version ? "." : "", version ? version : ""));
630 #endif
631 }
632
633 /*
634 * This is really gross: we need to free up JS function slots when then list
635 * is freed, but there's no way for us to know that's happening. So we
636 * interpose on nvlist_free() here, checking for function slots to free iff
637 * this is a list that has a V8 JS function handle in it. Lists created by
638 * someone else, even if they have uint64 arrays in them, are passed through.
639 * This whole thing makes me want to cry. Why can't we just have a decent
640 * JS VM?!
641 */
642 extern "C" void
643 nvlist_free(nvlist_t *lp)
644 {
645 uint64_t *vp;
646 uint_t nv;
647 nvpair_t *pp = NULL;
648
649 if (lp == NULL)
650 return;
651
652 if (__real_nvlist_free == NULL) {
653 char *libname;
654 size_t len;
655 void *dlhdl;
656
657 len = library_name("nvpair", "1", NULL, 0) + 1;
658 libname = reinterpret_cast<char *>(alloca(len));
659 (void) library_name("nvpair", "1", libname, len);
660
661 dlhdl = dlopen(libname, RTLD_LAZY | RTLD_LOCAL);
662 if (dlhdl == NULL) {
663 v8plus_panic("unable to dlopen libnvpair: %s",
664 dlerror());
665 }
666 __real_nvlist_free = (void (*)(nvlist_t *))
667 dlsym(dlhdl, "nvlist_free");
668 if (__real_nvlist_free == NULL)
669 v8plus_panic("unable to find nvlist_free");
670 }
671
672 if (nvlist_exists(lp, V8PLUS_JSF_COOKIE)) {
673 while ((pp = nvlist_next_nvpair(lp, pp)) != NULL) {
674 if (nvpair_type(pp) != DATA_TYPE_UINT64_ARRAY)
675 continue;
676 if (nvpair_value_uint64_array(pp, &vp, &nv) != 0) {
677 v8plus_panic(
678 "unable to obtain callbach hash tag");
679 }
680 if (nv != 1) {
681 v8plus_panic(
682 "bad array size %u for callback hash tag",
683 nv);
684 }
685 v8plus_jsfunc_rele(*vp);
686 }
687 }
688
689 __real_nvlist_free(lp);
690 }
691
692 extern "C" int
693 nvpair_value_v8plus_jsfunc(const nvpair_t *pp, v8plus_jsfunc_t *vp)
694 {
695 uint64_t *lvp;
696 uint_t nv;
697 int err;
698
699 if ((err = nvpair_value_uint64_array((nvpair_t *)pp, &lvp, &nv)) != 0)
700 return (err);
701
702 *vp = *lvp;
703
704 return (0);
705 }
706
707 extern "C" void
708 v8plus_obj_hold(const void *cop)
709 {
710 v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop);
711 op->public_Ref();
712 }
713
714 extern "C" void
715 v8plus_obj_rele(const void *cop)
716 {
717 v8plus::ObjectWrap *op = v8plus::ObjectWrap::objlookup(cop);
718 op->public_Unref();
719 }