![]() |
RTBKit
0.9
Open-source framework to create real-time ad bidding systems.
|
00001 /* slot.cc 00002 Jeremy Barnes, 16 November 2010 00003 Copyright (c) 2010 Datacratic. All rights reserved. 00004 00005 Code to deal with slots. 00006 */ 00007 00008 #include "slot.h" 00009 #include "v8.h" 00010 #include "soa/js/js_utils.h" 00011 #include "soa/js/js_call.h" 00012 #include <boost/signals2.hpp> 00013 #include <boost/bind.hpp> 00014 #include "jml/arch/format.h" 00015 00016 00017 using namespace std; 00018 using namespace ML; 00019 00020 00021 namespace Datacratic { 00022 00023 bool inJsContext() 00024 { 00025 return true; 00026 return v8::Locker::IsLocked(); 00027 } 00028 00029 void enterJs(void * & locker) 00030 { 00031 locker = 0; 00032 if (v8::Locker::IsLocked()) return; 00033 v8::Locker::StartPreemption(1); // every one ms 00034 locker = new v8::Locker(); 00035 } 00036 00037 void exitJs(void * & locker_) 00038 { 00039 if (!locker_) return; 00040 v8::Locker * locker = (v8::Locker *)locker_; 00041 delete locker; 00042 locker_ = 0; 00043 } 00044 00045 /*****************************************************************************/ 00046 /* SLOT DISCONNECTOR */ 00047 /*****************************************************************************/ 00048 00049 SlotDisconnector:: 00050 SlotDisconnector(const boost::signals2::connection & connection) 00051 : boost::function<void (void)> 00052 (boost::bind(&boost::signals2::connection::disconnect, 00053 connection)) 00054 { 00055 } 00056 00057 00058 /*****************************************************************************/ 00059 /* SLOT */ 00060 /*****************************************************************************/ 00061 00062 Slot:: 00063 Slot(const Slot & other) 00064 : fn(other.fn), ops(other.ops), jsops(other.jsops), fntype(other.fntype) 00065 { 00066 switch (fntype) { 00067 case EMPTY: break; 00068 case BOOST: 00069 if (ops && fn) 00070 fn = (boost::function_base *)(ops(3, fn)); 00071 break; 00072 case JS: 00073 jsfn = new v8::Persistent<v8::Function> 00074 (v8::Persistent<v8::Function>::New(*jsfn)); 00075 break; 00076 default: 00077 throw Exception("wrong fntype"); 00078 } 00079 } 00080 00081 Slot:: 00082 Slot(Slot && other) 00083 : fn(other.fn), ops(other.ops), jsops(other.jsops), fntype(other.fntype) 00084 { 00085 other.fntype = EMPTY; 00086 } 00087 00088 Slot:: 00089 Slot(const v8::Handle<v8::Function> & fn) 00090 : jsfn(new v8::Persistent<v8::Function> 00091 (v8::Persistent<v8::Function>::New(fn))), 00092 fntype(JS) 00093 { 00094 if (fn.IsEmpty() || jsfn->IsEmpty()) 00095 throw Exception("invalid function"); 00096 } 00097 00098 Slot:: 00099 Slot(const v8::Handle<v8::Value> & fn) 00100 : jsfn(new v8::Persistent<v8::Function> 00101 (v8::Persistent<v8::Function>::New 00102 (v8::Handle<v8::Function> 00103 (v8::Function::Cast(*fn))))), 00104 fntype(JS) 00105 { 00106 if (fn.IsEmpty()) 00107 throw Exception("invalid function"); 00108 if (jsfn->IsEmpty()) 00109 throw Exception("Non-function JS value " + JS::cstr(fn) + " passed to slot"); 00110 } 00111 00112 Slot:: 00113 ~Slot() 00114 { 00115 free(); 00116 } 00117 00118 void 00119 Slot:: 00120 free() 00121 { 00122 switch (fntype) { 00123 case EMPTY: break; 00124 case BOOST: 00125 if (ops) ops(1, fn); 00126 break; 00127 case JS: 00128 if (jsfn) { 00129 jsfn->Dispose(); 00130 jsfn->Clear(); 00131 delete jsfn; 00132 } 00133 break; 00134 default: 00135 throw Exception("Slot::free(): wrong type"); 00136 } 00137 00138 fntype = EMPTY; 00139 } 00140 00141 Slot & 00142 Slot:: 00143 operator = (const Slot & other) 00144 { 00145 Slot new_me(other); 00146 swap(new_me); 00147 return *this; 00148 } 00149 00150 Slot & 00151 Slot:: 00152 operator = (Slot && other) 00153 { 00154 Slot new_me(other); 00155 swap(other); 00156 return *this; 00157 } 00158 00159 void 00160 Slot:: 00161 swap(Slot & other) 00162 { 00163 std::swap(fntype, other.fntype); 00164 std::swap(fn, other.fn); 00165 std::swap(ops, other.ops); 00166 std::swap(jsops, other.jsops); 00167 } 00168 00169 std::string 00170 Slot:: 00171 print() const 00172 { 00173 switch (fntype) { 00174 case EMPTY: 00175 return "(empty)"; 00176 case BOOST: 00177 return "(c++) " + ML::demangle(type()) + " as " 00178 + ML::demangle(fn->target_type()); 00179 case JS: 00180 return "(js) " + JS::cstr(*jsfn); 00181 default: 00182 return "(invalid type) " + ML::format("%d", fntype); 00183 } 00184 } 00185 00186 v8::Handle<v8::Value> 00187 Slot:: 00188 call(const v8::Arguments & args) const 00189 { 00190 switch (fntype) { 00191 case EMPTY: 00192 throw Exception("cannot call an empty function"); 00193 case BOOST: { 00194 if (!jsops) 00195 throw ML::Exception("no javascript translator"); 00196 JS::JSCallsBoost op = (JS::JSCallsBoost)jsops; 00197 00198 v8::HandleScope scope; 00199 00200 v8::Handle<v8::Value> result; 00201 op(0, *fn, args, result); 00202 return scope.Close(result); 00203 } 00204 case JS: { 00205 // Forward directly to JS 00206 v8::HandleScope scope; 00207 vector<v8::Local<v8::Value> > vals(args.Length()); 00208 for (unsigned i = 0; i < vals.size(); ++i) 00209 vals[i] = args[i]; 00210 return scope.Close((*jsfn)->Call(args.This(), args.Length(), 00211 &vals[0])); 00212 } 00213 default: 00214 throw Exception("invalid fn type"); 00215 } 00216 } 00217 00218 v8::Handle<v8::Value> 00219 Slot:: 00220 call(const v8::Handle<v8::Object> & This, 00221 int argc, v8::Handle<v8::Value> argv[]) const 00222 { 00223 switch (fntype) { 00224 case EMPTY: 00225 throw Exception("cannot call an empty function"); 00226 case BOOST: { 00227 if (!jsops) 00228 throw ML::Exception("no javascript translator"); 00229 JS::JSCallsBoost op = (JS::JSCallsBoost)jsops; 00230 00231 v8::HandleScope scope; 00232 00233 v8::Handle<v8::Value> result; 00234 op(0, *fn, JS::JSArgs(This, argc, argv), result); 00235 00236 return scope.Close(result); 00237 } 00238 case JS: 00239 // Forward directly to JS 00240 return (*jsfn)->Call(This, argc, argv); 00241 default: 00242 throw Exception("invalid fn type"); 00243 } 00244 } 00245 00246 const std::type_info & 00247 Slot:: 00248 type() const 00249 { 00250 switch (fntype) { 00251 case EMPTY: 00252 return typeid(void); 00253 case BOOST: { 00254 std::type_info * p = 0; 00255 ops(0, &p); 00256 return *p; 00257 } 00258 case JS: 00259 return typeid(v8::Function); 00260 default: 00261 throw Exception("Slot::type(): invalid type"); 00262 } 00263 } 00264 00265 namespace JS { 00266 00267 Slot from_js(const JSValue & val, Slot *) 00268 { 00269 return Slot(from_js(val, (v8::Handle<v8::Function> *)0)); 00270 } 00271 00272 } // namespace JS 00273 00274 } // namespace Datacratic