1 /* 2 * Copyright (c) 2012 Joyent, Inc. All rights reserved. 3 */ 4 5 #include <sys/types.h> 6 #include <string.h> 7 #include <new> 8 #include <unordered_map> 9 #include <stdlib.h> 10 #include <node.h> 11 #include "v8plus_impl.h" 12 #include "v8plus_glue.h" 13 14 #define METHOD_NAME_FMT "__v8plus_%s_%s" 15 16 v8::Persistent<v8::Function> v8plus::ObjectWrap::_constructor; 17 v8plus_method_descr_t *v8plus::ObjectWrap::_mtbl; 18 v8plus_static_descr_t *v8plus::ObjectWrap::_stbl; 19 std::unordered_map<void *, v8plus::ObjectWrap *> v8plus::ObjectWrap::_objhash; 20 21 static char * 22 function_name(const char *lambda) 23 { 24 char *fn; 25 size_t len; 26 27 len = snprintf(NULL, 0, METHOD_NAME_FMT, 28 v8plus_js_class_name, lambda); 29 if ((fn = (char *)malloc(len + 1)) == NULL) 30 v8plus_panic("out of memory for function name for %s", lambda); 31 32 (void) snprintf(fn, len + 1, METHOD_NAME_FMT, 33 v8plus_js_class_name, lambda); 34 35 return (fn); 36 } 37 38 void 39 v8plus::ObjectWrap::init(v8::Handle<v8::Object> target) 40 { 41 uint_t i; 42 43 if (v8plus_static_method_count > 0) { 44 const v8plus_static_descr_t *sdp; 45 46 _stbl = new (std::nothrow) 47 v8plus_static_descr_t[v8plus_static_method_count]; 48 if (_stbl == NULL) 49 v8plus_panic("out of memory for static method table"); 50 51 for (i = 0; i < v8plus_static_method_count; i++) { 52 v8::Local<v8::FunctionTemplate> fth = 53 v8::FunctionTemplate::New(_static_entry); 54 v8::Local<v8::Function> fh = fth->GetFunction(); 55 sdp = &v8plus_static_methods[i]; 56 57 _stbl[i].sd_name = function_name(sdp->sd_name); 58 _stbl[i].sd_c_func = sdp->sd_c_func; 59 60 fh->SetName(v8::String::New(_stbl[i].sd_name)); 61 62 target->Set(v8::String::NewSymbol(sdp->sd_name), fh); 63 } 64 } 65 66 67 if (v8plus_method_count > 0) { 68 v8::Local<v8::FunctionTemplate> tpl = 69 v8::FunctionTemplate::New(_new); 70 const v8plus_method_descr_t *mdp; 71 72 _mtbl = new (std::nothrow) 73 v8plus_method_descr_t[v8plus_method_count]; 74 if (_mtbl == NULL) 75 v8plus_panic("out of memory for method table"); 76 77 tpl->SetClassName(v8::String::NewSymbol(v8plus_js_class_name)); 78 tpl->InstanceTemplate()->SetInternalFieldCount( 79 v8plus_method_count); 80 81 for (i = 0; i < v8plus_method_count; i++) { 82 v8::Local<v8::FunctionTemplate> fth = 83 v8::FunctionTemplate::New(_entry); 84 v8::Local<v8::Function> fh = fth->GetFunction(); 85 mdp = &v8plus_methods[i]; 86 87 _mtbl[i].md_name = function_name(mdp->md_name); 88 _mtbl[i].md_c_func = mdp->md_c_func; 89 90 fh->SetName(v8::String::New(_mtbl[i].md_name)); 91 92 tpl->PrototypeTemplate()->Set( 93 v8::String::NewSymbol(mdp->md_name), fh); 94 } 95 96 _constructor = 97 v8::Persistent<v8::Function>::New(tpl->GetFunction()); 98 99 target->Set(v8::String::NewSymbol(v8plus_js_factory_name), 100 v8::FunctionTemplate::New( 101 v8plus::ObjectWrap::cons)->GetFunction()); 102 } 103 104 v8plus_crossthread_init(); 105 } 106 107 v8::Handle<v8::Value> 108 v8plus::ObjectWrap::_new(const v8::Arguments &args) 109 { 110 v8::HandleScope scope; 111 v8plus::ObjectWrap *op = new v8plus::ObjectWrap(); 112 nvlist_t *c_excp; 113 nvlist_t *c_args; 114 115 if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL) 116 return (V8PLUS_THROW_DEFAULT()); 117 118 c_excp = v8plus_ctor(c_args, &op->_c_impl); 119 nvlist_free(c_args); 120 if (op->_c_impl == NULL) { 121 if (c_excp == NULL) { 122 return (V8PLUS_THROW_DEFAULT()); 123 } else { 124 return (V8PLUS_THROW_DECORATED(c_excp)); 125 } 126 } 127 128 _objhash.insert(std::make_pair(op->_c_impl, op)); 129 op->Wrap(args.This()); 130 131 return (args.This()); 132 } 133 134 v8plus::ObjectWrap::~ObjectWrap() 135 { 136 v8plus_dtor(_c_impl); 137 (void) _objhash.erase(_c_impl); 138 } 139 140 v8::Handle<v8::Value> 141 v8plus::ObjectWrap::cons(const v8::Arguments &args) 142 { 143 v8::HandleScope scope; 144 const unsigned argc = 1; 145 v8::Handle<v8::Value> argv[argc] = { args[0] }; 146 v8::Local<v8::Object> instance = _constructor->NewInstance(argc, argv); 147 148 return (scope.Close(instance)); 149 } 150 151 v8plus::ObjectWrap * 152 v8plus::ObjectWrap::objlookup(const void *cop) 153 { 154 std::unordered_map<void *, v8plus::ObjectWrap *>::iterator it; 155 156 if ((it = _objhash.find(const_cast<void *>(cop))) == _objhash.end()) 157 v8plus_panic("unable to find C++ wrapper for %p\n", cop); 158 159 return (it->second); 160 } 161 162 /* 163 * This is the entry point for all methods. We will start by demultiplexing 164 * out the C method from the function name by which we were called. There is 165 * probably some mechanism by which overly clever JavaScript code could make 166 * this not match the actual name; this will kill your Node process, so don't 167 * get cute. 168 */ 169 v8::Handle<v8::Value> 170 v8plus::ObjectWrap::_entry(const v8::Arguments &args) 171 { 172 v8::HandleScope scope; 173 v8plus::ObjectWrap *op = 174 node::ObjectWrap::Unwrap<v8plus::ObjectWrap>(args.This()); 175 nvlist_t *c_args; 176 nvlist_t *c_out; 177 nvlist_t *excp; 178 nvpair_t *rpp; 179 v8::Local<v8::String> self = args.Callee()->GetName()->ToString(); 180 v8::String::Utf8Value selfsv(self); 181 const char *fn = *selfsv; 182 const v8plus_method_descr_t *mdp; 183 v8plus_c_method_f c_method = NULL; 184 uint_t i; 185 186 for (i = 0; i < v8plus_method_count; i++) { 187 mdp = &_mtbl[i]; 188 if (strcmp(mdp->md_name, fn) == 0) { 189 c_method = mdp->md_c_func; 190 break; 191 } 192 } 193 194 if (c_method == NULL) 195 v8plus_panic("impossible method name %s\n", fn); 196 197 if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL) 198 return (V8PLUS_THROW_DEFAULT()); 199 200 c_out = c_method(op->_c_impl, c_args); 201 nvlist_free(c_args); 202 203 if (c_out == NULL) { 204 if (_v8plus_errno == V8PLUSERR_NOERROR) 205 return (scope.Close(v8::Undefined())); 206 else 207 return (V8PLUS_THROW_DEFAULT()); 208 } else { 209 if (nvlist_lookup_nvlist(c_out, "err", &excp) == 0) { 210 v8::Handle<v8::Value> x = V8PLUS_THROW_DECORATED(excp); 211 nvlist_free(c_out); 212 return (x); 213 } else if (nvlist_lookup_nvpair(c_out, "res", &rpp) == 0) { 214 v8::Handle<v8::Value> r = 215 v8plus::nvpair_to_v8_Value(rpp); 216 nvlist_free(c_out); 217 return (scope.Close(r)); 218 } else { 219 v8plus_panic("bad encoded object in return"); 220 } 221 } 222 223 /*NOTREACHED*/ 224 return (v8::Undefined()); 225 } 226 227 v8::Handle<v8::Value> 228 v8plus::ObjectWrap::_static_entry(const v8::Arguments &args) 229 { 230 v8::HandleScope scope; 231 nvlist_t *c_args; 232 nvlist_t *c_out; 233 nvlist_t *excp; 234 nvpair_t *rpp; 235 v8::Local<v8::String> self = args.Callee()->GetName()->ToString(); 236 v8::String::Utf8Value selfsv(self); 237 const char *fn = *selfsv; 238 const v8plus_static_descr_t *sdp; 239 v8plus_c_static_f c_static = NULL; 240 uint_t i; 241 242 for (i = 0; i < v8plus_static_method_count; i++) { 243 sdp = &_stbl[i]; 244 if (strcmp(sdp->sd_name, fn) == 0) { 245 c_static = sdp->sd_c_func; 246 break; 247 } 248 } 249 250 if (c_static == NULL) 251 v8plus_panic("impossible static method name %s\n", fn); 252 253 if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL) 254 return (V8PLUS_THROW_DEFAULT()); 255 256 c_out = c_static(c_args); 257 nvlist_free(c_args); 258 259 if (c_out == NULL) { 260 if (_v8plus_errno == V8PLUSERR_NOERROR) 261 return (scope.Close(v8::Undefined())); 262 else 263 return (V8PLUS_THROW_DEFAULT()); 264 } else { 265 if (nvlist_lookup_nvlist(c_out, "err", &excp) == 0) { 266 v8::Handle<v8::Value> x = V8PLUS_THROW_DECORATED(excp); 267 nvlist_free(c_out); 268 return (x); 269 } else if (nvlist_lookup_nvpair(c_out, "res", &rpp) == 0) { 270 v8::Handle<v8::Value> r = 271 v8plus::nvpair_to_v8_Value(rpp); 272 nvlist_free(c_out); 273 return (scope.Close(r)); 274 } else { 275 v8plus_panic("bad encoded object in return"); 276 } 277 } 278 279 /*NOTREACHED*/ 280 return (v8::Undefined()); 281 } 282 283 v8::Handle<v8::Value> 284 v8plus::ObjectWrap::call(const char *name, 285 int argc, v8::Handle<v8::Value> argv[]) 286 { 287 v8::Handle<v8::Value> v = v8::Undefined(); 288 v8::Local<v8::Value> f = handle_->Get(v8::String::NewSymbol(name)); 289 290 /* 291 * XXX - we'd like to throw here, but for some reason our TryCatch 292 * block doesn't seem to handle the exception. 293 */ 294 if (!f->IsFunction()) 295 return (v8::Undefined()); 296 297 #ifdef NODE_MAKECALLBACK_RETURN 298 v = 299 #endif 300 node::MakeCallback(handle_, name, argc, argv); 301 302 return (v); 303 } 304 305 void 306 v8plus::ObjectWrap::public_Ref(void) 307 { 308 this->Ref(); 309 } 310 311 void 312 v8plus::ObjectWrap::public_Unref(void) 313 { 314 this->Unref(); 315 } 316 317 extern "C" void 318 init(v8::Handle<v8::Object> target) 319 { 320 v8plus::ObjectWrap::init(target); 321 }