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 105 v8::Handle<v8::Value> 106 v8plus::ObjectWrap::_new(const v8::Arguments &args) 107 { 108 v8::HandleScope scope; 109 v8plus::ObjectWrap *op = new v8plus::ObjectWrap(); 110 nvlist_t *c_excp; 111 nvlist_t *c_args; 112 113 if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL) 114 return (V8PLUS_THROW_DEFAULT()); 115 116 c_excp = v8plus_ctor(c_args, &op->_c_impl); 117 nvlist_free(c_args); 118 if (op->_c_impl == NULL) { 119 if (c_excp == NULL) { 120 return (V8PLUS_THROW_DEFAULT()); 121 } else { 122 return (V8PLUS_THROW_DECORATED(c_excp)); 123 } 124 } 125 126 _objhash.insert(std::make_pair(op->_c_impl, op)); 127 op->Wrap(args.This()); 128 129 return (args.This()); 130 } 131 132 v8plus::ObjectWrap::~ObjectWrap() 133 { 134 v8plus_dtor(_c_impl); 135 (void) _objhash.erase(_c_impl); 136 } 137 138 v8::Handle<v8::Value> 139 v8plus::ObjectWrap::cons(const v8::Arguments &args) 140 { 141 v8::HandleScope scope; 142 const unsigned argc = 1; 143 v8::Handle<v8::Value> argv[argc] = { args[0] }; 144 v8::Local<v8::Object> instance = _constructor->NewInstance(argc, argv); 145 146 return (scope.Close(instance)); 147 } 148 149 v8plus::ObjectWrap * 150 v8plus::ObjectWrap::objlookup(const void *cop) 151 { 152 std::unordered_map<void *, v8plus::ObjectWrap *>::iterator it; 153 154 if ((it = _objhash.find(const_cast<void *>(cop))) == _objhash.end()) 155 v8plus_panic("unable to find C++ wrapper for %p\n", cop); 156 157 return (it->second); 158 } 159 160 /* 161 * This is the entry point for all methods. We will start by demultiplexing 162 * out the C method from the function name by which we were called. There is 163 * probably some mechanism by which overly clever JavaScript code could make 164 * this not match the actual name; this will kill your Node process, so don't 165 * get cute. 166 */ 167 v8::Handle<v8::Value> 168 v8plus::ObjectWrap::_entry(const v8::Arguments &args) 169 { 170 v8::HandleScope scope; 171 v8plus::ObjectWrap *op = 172 node::ObjectWrap::Unwrap<v8plus::ObjectWrap>(args.This()); 173 nvlist_t *c_args; 174 nvlist_t *c_out; 175 nvlist_t *excp; 176 nvpair_t *rpp; 177 v8::Local<v8::String> self = args.Callee()->GetName()->ToString(); 178 v8::String::Utf8Value selfsv(self); 179 const char *fn = *selfsv; 180 const v8plus_method_descr_t *mdp; 181 v8plus_c_method_f c_method = NULL; 182 uint_t i; 183 184 for (i = 0; i < v8plus_method_count; i++) { 185 mdp = &_mtbl[i]; 186 if (strcmp(mdp->md_name, fn) == 0) { 187 c_method = mdp->md_c_func; 188 break; 189 } 190 } 191 192 if (c_method == NULL) 193 v8plus_panic("impossible method name %s\n", fn); 194 195 if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL) 196 return (V8PLUS_THROW_DEFAULT()); 197 198 c_out = c_method(op->_c_impl, c_args); 199 nvlist_free(c_args); 200 201 if (c_out == NULL) { 202 if (_v8plus_errno == V8PLUSERR_NOERROR) 203 return (scope.Close(v8::Undefined())); 204 else 205 return (V8PLUS_THROW_DEFAULT()); 206 } else { 207 if (nvlist_lookup_nvlist(c_out, "err", &excp) == 0) { 208 v8::Handle<v8::Value> x = V8PLUS_THROW_DECORATED(excp); 209 nvlist_free(c_out); 210 return (x); 211 } else if (nvlist_lookup_nvpair(c_out, "res", &rpp) == 0) { 212 v8::Handle<v8::Value> r = 213 v8plus::nvpair_to_v8_Value(rpp); 214 nvlist_free(c_out); 215 return (scope.Close(r)); 216 } else { 217 v8plus_panic("bad encoded object in return"); 218 } 219 } 220 221 /*NOTREACHED*/ 222 return (v8::Undefined()); 223 } 224 225 v8::Handle<v8::Value> 226 v8plus::ObjectWrap::_static_entry(const v8::Arguments &args) 227 { 228 v8::HandleScope scope; 229 nvlist_t *c_args; 230 nvlist_t *c_out; 231 nvlist_t *excp; 232 nvpair_t *rpp; 233 v8::Local<v8::String> self = args.Callee()->GetName()->ToString(); 234 v8::String::Utf8Value selfsv(self); 235 const char *fn = *selfsv; 236 const v8plus_static_descr_t *sdp; 237 v8plus_c_static_f c_static = NULL; 238 uint_t i; 239 240 for (i = 0; i < v8plus_static_method_count; i++) { 241 sdp = &_stbl[i]; 242 if (strcmp(sdp->sd_name, fn) == 0) { 243 c_static = sdp->sd_c_func; 244 break; 245 } 246 } 247 248 if (c_static == NULL) 249 v8plus_panic("impossible static method name %s\n", fn); 250 251 if ((c_args = v8plus::v8_Arguments_to_nvlist(args)) == NULL) 252 return (V8PLUS_THROW_DEFAULT()); 253 254 c_out = c_static(c_args); 255 nvlist_free(c_args); 256 257 if (c_out == NULL) { 258 if (_v8plus_errno == V8PLUSERR_NOERROR) 259 return (scope.Close(v8::Undefined())); 260 else 261 return (V8PLUS_THROW_DEFAULT()); 262 } else { 263 if (nvlist_lookup_nvlist(c_out, "err", &excp) == 0) { 264 v8::Handle<v8::Value> x = V8PLUS_THROW_DECORATED(excp); 265 nvlist_free(c_out); 266 return (x); 267 } else if (nvlist_lookup_nvpair(c_out, "res", &rpp) == 0) { 268 v8::Handle<v8::Value> r = 269 v8plus::nvpair_to_v8_Value(rpp); 270 nvlist_free(c_out); 271 return (scope.Close(r)); 272 } else { 273 v8plus_panic("bad encoded object in return"); 274 } 275 } 276 277 /*NOTREACHED*/ 278 return (v8::Undefined()); 279 } 280 281 v8::Handle<v8::Value> 282 v8plus::ObjectWrap::call(const char *name, 283 int argc, v8::Handle<v8::Value> argv[]) 284 { 285 v8::Handle<v8::Value> v = v8::Undefined(); 286 v8::Local<v8::Value> f = handle_->Get(v8::String::NewSymbol(name)); 287 288 /* 289 * XXX - we'd like to throw here, but for some reason our TryCatch 290 * block doesn't seem to handle the exception. 291 */ 292 if (!f->IsFunction()) 293 return (v8::Undefined()); 294 295 #ifdef NODE_MAKECALLBACK_RETURN 296 v = 297 #endif 298 node::MakeCallback(handle_, name, argc, argv); 299 300 return (v); 301 } 302 303 void 304 v8plus::ObjectWrap::public_Ref(void) 305 { 306 this->Ref(); 307 } 308 309 void 310 v8plus::ObjectWrap::public_Unref(void) 311 { 312 this->Unref(); 313 } 314 315 extern "C" void 316 init(v8::Handle<v8::Object> target) 317 { 318 v8plus::ObjectWrap::init(target); 319 }