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 }