RTBKit  0.9
Open-source framework to create real-time ad bidding systems.
soa/js/js_wrapped.cc
00001 /* js_wrapped.cc
00002    Jeremy Barnes, 15 July 2010
00003    Copyright (c) 2010 Datacratic.  All rights reserved.
00004 
00005    Implementation of javascript wrapper.
00006 
00007    Some code is from node_object_wrap.h, from node.js.  Its license is
00008    included here:
00009 
00010    Copyright 2009, 2010 Ryan Lienhart Dahl. All rights reserved.
00011    Permission is hereby granted, free of charge, to any person obtaining a copy
00012    of this software and associated documentation files (the "Software"), to
00013    deal in the Software without restriction, including without limitation the
00014    rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
00015    sell copies of the Software, and to permit persons to whom the Software is
00016    furnished to do so, subject to the following conditions:
00017    
00018    The above copyright notice and this permission notice shall be included in
00019    all copies or substantial portions of the Software.
00020    
00021    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00022    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00023    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00024    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00025    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00026    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
00027    IN THE SOFTWARE. 
00028 */
00029 
00030 #include "js_wrapped.h"
00031 #include <iostream>
00032 
00033 
00034 using namespace std;
00035 using namespace v8;
00036 
00037 
00038 namespace Datacratic {
00039 namespace JS {
00040 
00041 
00042 const std::type_info & getWrapperTypeInfo(v8::Handle<v8::Value> handle)
00043 {
00044     ExcAssert(!handle.IsEmpty());
00045     ExcAssert(handle->IsObject());
00046 
00047     v8::Handle<v8::Object> object(v8::Object::Cast(*handle));
00048 
00049     ExcAssert(object->InternalFieldCount() == 2);
00050 
00051     return *static_cast<const std::type_info *>
00052         (v8::Handle<v8::External>::Cast
00053          (object->GetInternalField(1))->Value());
00054 }
00055 
00056 
00057 
00058 /*****************************************************************************/
00059 /* JSWRAPPEDBASE                                                             */
00060 /*****************************************************************************/
00061 
00062 JSWrappedBase::
00063 ~JSWrappedBase ()
00064 {
00065     if (js_object_.IsEmpty()) return;
00066     ExcAssert(js_object_.IsNearDeath());
00067     js_object_->SetInternalField(0, v8::Undefined());
00068     js_object_->SetInternalField(1, v8::Undefined());
00069     js_object_.Dispose();
00070     js_object_.Clear();
00071 }
00072 
00073 void
00074 JSWrappedBase::
00075 wrap(v8::Handle<v8::Object> handle,
00076      size_t size_in_bytes,
00077      const std::type_info & wrappedType)
00078 {
00079     size_in_bytes_ = size_in_bytes;
00080     ExcAssert(js_object_.IsEmpty());
00081 
00082     if (handle->InternalFieldCount() == 0) {
00083         throw ML::Exception("InternalFieldCount is zero; are you forgetting "
00084                             "to use 'new' for " + getJsTypeName());
00085     }
00086 
00087     ExcAssert(handle->InternalFieldCount() == 2);
00088 
00089     js_object_ = v8::Persistent<v8::Object>::New(handle);
00090     js_object_->SetInternalField(0, v8::External::New(this));
00091     js_object_->SetInternalField(1, v8::External::New((void *)&wrappedType));
00092     v8::V8::AdjustAmountOfExternalAllocatedMemory(size_in_bytes);
00093     registerForGarbageCollection();
00094 }
00095 
00096 void
00097 JSWrappedBase::
00098 registerForGarbageCollection()
00099 {
00100     js_object_.MakeWeak(this, getGarbageCollectionCallback());
00101 }
00102 
00103 void
00104 JSWrappedBase::
00105 ref()
00106 {
00107     ExcAssert(!js_object_.IsEmpty());
00108     refs_++;
00109     js_object_.ClearWeak();
00110 }
00111 
00112 void
00113 JSWrappedBase::
00114 unref()
00115 {
00116     ExcAssert(!js_object_.IsEmpty());
00117     ExcAssert(!js_object_.IsWeak());
00118     ExcAssert(refs_ > 0);
00119     if (--refs_ == 0) { registerForGarbageCollection(); }
00120 }
00121 
00122 void
00123 JSWrappedBase::
00124 dispose()
00125 {
00126     //cerr << "disposing of " << ML::type_name(*this) << " at " << this
00127     //     << endl;
00128     delete this;
00129 }
00130 
00131 v8::WeakReferenceCallback
00132 JSWrappedBase::
00133 getGarbageCollectionCallback() const
00134 {
00135     return garbageCollectionCallback;
00136 }
00137    
00138 void
00139 JSWrappedBase::
00140 garbageCollectionCallback(v8::Persistent<v8::Value> value, void * data)
00141 {
00142     try {
00143         JSWrappedBase * obj = reinterpret_cast<JSWrappedBase *>(data);
00144         ExcAssert(value == obj->js_object_);
00145         ExcAssert(!obj->refs_);
00146         if (value.IsNearDeath()) {
00147             v8::V8::AdjustAmountOfExternalAllocatedMemory(-obj->size_in_bytes_);
00148             obj->size_in_bytes_ = 0;
00149             obj->dispose();
00150         }
00151     } catch (const std::exception & exc) {
00152         cerr << "WARNING: exception thrown in GC: " << exc.what() << endl;
00153     } catch (...) {
00154         cerr << "WARNING: exception thrown in GC: unknown" << endl;
00155     }
00156 }
00157 
00158 } // namespace JS
00159 } // namespace Datacratic
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator