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