|
@ -18,11 +18,29 @@ |
|
|
#include "v8.h" |
|
|
#include "v8.h" |
|
|
#include "node.h" |
|
|
#include "node.h" |
|
|
|
|
|
|
|
|
using namespace v8; |
|
|
|
|
|
using namespace node; |
|
|
|
|
|
|
|
|
|
|
|
namespace { |
|
|
namespace { |
|
|
|
|
|
|
|
|
|
|
|
using node::FatalException; |
|
|
|
|
|
using v8::Array; |
|
|
|
|
|
using v8::Boolean; |
|
|
|
|
|
using v8::Exception; |
|
|
|
|
|
using v8::Function; |
|
|
|
|
|
using v8::FunctionTemplate; |
|
|
|
|
|
using v8::FunctionCallbackInfo; |
|
|
|
|
|
using v8::Handle; |
|
|
|
|
|
using v8::HandleScope; |
|
|
|
|
|
using v8::Integer; |
|
|
|
|
|
using v8::Isolate; |
|
|
|
|
|
using v8::Local; |
|
|
|
|
|
using v8::None; |
|
|
|
|
|
using v8::Object; |
|
|
|
|
|
using v8::ObjectTemplate; |
|
|
|
|
|
using v8::Persistent; |
|
|
|
|
|
using v8::PropertyCallbackInfo; |
|
|
|
|
|
using v8::Value; |
|
|
|
|
|
using v8::String; |
|
|
|
|
|
using v8::ThrowException; |
|
|
|
|
|
using v8::TryCatch; |
|
|
|
|
|
|
|
|
typedef struct proxy_container { |
|
|
typedef struct proxy_container { |
|
|
Persistent<Object> proxy; |
|
|
Persistent<Object> proxy; |
|
@ -46,14 +64,16 @@ Handle<Object> Unwrap(Handle<Object> proxy) { |
|
|
assert(!IsDead(proxy)); |
|
|
assert(!IsDead(proxy)); |
|
|
proxy_container *cont = reinterpret_cast<proxy_container*>( |
|
|
proxy_container *cont = reinterpret_cast<proxy_container*>( |
|
|
proxy->GetAlignedPointerFromInternalField(0)); |
|
|
proxy->GetAlignedPointerFromInternalField(0)); |
|
|
return cont->target; |
|
|
Isolate* isolate = Isolate::GetCurrent(); |
|
|
|
|
|
return Local<Object>::New(isolate, cont->target); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Handle<Array> GetCallbacks(Handle<Object> proxy) { |
|
|
Handle<Array> GetCallbacks(Handle<Object> proxy) { |
|
|
proxy_container *cont = reinterpret_cast<proxy_container*>( |
|
|
proxy_container *cont = reinterpret_cast<proxy_container*>( |
|
|
proxy->GetAlignedPointerFromInternalField(0)); |
|
|
proxy->GetAlignedPointerFromInternalField(0)); |
|
|
assert(cont != NULL); |
|
|
assert(cont != NULL); |
|
|
return cont->callbacks; |
|
|
Isolate* isolate = Isolate::GetCurrent(); |
|
|
|
|
|
return Local<Array>::New(isolate, cont->callbacks); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -64,67 +84,65 @@ Handle<Array> GetCallbacks(Handle<Object> proxy) { |
|
|
if (!dead) obj = Unwrap(info.This()); \ |
|
|
if (!dead) obj = Unwrap(info.This()); \ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> WeakNamedPropertyGetter(Local<String> property, |
|
|
void WeakNamedPropertyGetter(Local<String> property, |
|
|
const AccessorInfo& info) { |
|
|
const PropertyCallbackInfo<Value>& info) { |
|
|
UNWRAP |
|
|
UNWRAP |
|
|
return dead ? Local<Value>() : obj->Get(property); |
|
|
if (!dead) info.GetReturnValue().Set(obj->Get(property)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> WeakNamedPropertySetter(Local<String> property, |
|
|
void WeakNamedPropertySetter(Local<String> property, |
|
|
Local<Value> value, |
|
|
Local<Value> value, |
|
|
const AccessorInfo& info) { |
|
|
const PropertyCallbackInfo<Value>& info) { |
|
|
UNWRAP |
|
|
UNWRAP |
|
|
if (!dead) obj->Set(property, value); |
|
|
if (!dead) obj->Set(property, value); |
|
|
return value; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Integer> WeakNamedPropertyQuery(Local<String> property, |
|
|
void WeakNamedPropertyQuery(Local<String> property, |
|
|
const AccessorInfo& info) { |
|
|
const PropertyCallbackInfo<Integer>& info) { |
|
|
return HandleScope().Close(Integer::New(None)); |
|
|
info.GetReturnValue().Set(None); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Boolean> WeakNamedPropertyDeleter(Local<String> property, |
|
|
void WeakNamedPropertyDeleter(Local<String> property, |
|
|
const AccessorInfo& info) { |
|
|
const PropertyCallbackInfo<Boolean>& info) { |
|
|
UNWRAP |
|
|
UNWRAP |
|
|
return Boolean::New(!dead && obj->Delete(property)); |
|
|
info.GetReturnValue().Set(!dead && obj->Delete(property)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> WeakIndexedPropertyGetter(uint32_t index, |
|
|
void WeakIndexedPropertyGetter(uint32_t index, |
|
|
const AccessorInfo& info) { |
|
|
const PropertyCallbackInfo<Value>& info) { |
|
|
UNWRAP |
|
|
UNWRAP |
|
|
return dead ? Local<Value>() : obj->Get(index); |
|
|
if (!dead) info.GetReturnValue().Set(obj->Get(index)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> WeakIndexedPropertySetter(uint32_t index, |
|
|
void WeakIndexedPropertySetter(uint32_t index, |
|
|
Local<Value> value, |
|
|
Local<Value> value, |
|
|
const AccessorInfo& info) { |
|
|
const PropertyCallbackInfo<Value>& info) { |
|
|
UNWRAP |
|
|
UNWRAP |
|
|
if (!dead) obj->Set(index, value); |
|
|
if (!dead) obj->Set(index, value); |
|
|
return value; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Integer> WeakIndexedPropertyQuery(uint32_t index, |
|
|
void WeakIndexedPropertyQuery(uint32_t index, |
|
|
const AccessorInfo& info) { |
|
|
const PropertyCallbackInfo<Integer>& info) { |
|
|
return HandleScope().Close(Integer::New(None)); |
|
|
info.GetReturnValue().Set(None); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Boolean> WeakIndexedPropertyDeleter(uint32_t index, |
|
|
void WeakIndexedPropertyDeleter(uint32_t index, |
|
|
const AccessorInfo& info) { |
|
|
const PropertyCallbackInfo<Boolean>& info) { |
|
|
UNWRAP |
|
|
UNWRAP |
|
|
return Boolean::New(!dead && obj->Delete(index)); |
|
|
info.GetReturnValue().Set(!dead && obj->Delete(index)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Array> WeakPropertyEnumerator(const AccessorInfo& info) { |
|
|
void WeakPropertyEnumerator(const PropertyCallbackInfo<Array>& info) { |
|
|
UNWRAP |
|
|
UNWRAP |
|
|
return HandleScope().Close(dead ? Array::New(0) : obj->GetPropertyNames()); |
|
|
info.GetReturnValue().Set(dead ? Array::New(0) : obj->GetPropertyNames()); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -137,19 +155,20 @@ void AddCallback(Handle<Object> proxy, Handle<Function> callback) { |
|
|
void TargetCallback(Isolate* isolate, Persistent<Object>* ptarget, void* arg) { |
|
|
void TargetCallback(Isolate* isolate, Persistent<Object>* ptarget, void* arg) { |
|
|
HandleScope scope(isolate); |
|
|
HandleScope scope(isolate); |
|
|
|
|
|
|
|
|
Persistent<Object> target = *ptarget; |
|
|
Local<Object> target = Local<Object>::New(isolate, *ptarget); |
|
|
assert(target.IsNearDeath()); |
|
|
assert((*ptarget).IsNearDeath()); |
|
|
|
|
|
|
|
|
proxy_container *cont = reinterpret_cast<proxy_container*>(arg); |
|
|
proxy_container *cont = reinterpret_cast<proxy_container*>(arg); |
|
|
|
|
|
|
|
|
// invoke any listening callbacks
|
|
|
// invoke any listening callbacks
|
|
|
uint32_t len = cont->callbacks->Length(); |
|
|
Local<Array> callbacks = Local<Array>::New(isolate, cont->callbacks); |
|
|
|
|
|
uint32_t len = callbacks->Length(); |
|
|
Handle<Value> argv[1]; |
|
|
Handle<Value> argv[1]; |
|
|
argv[0] = target; |
|
|
argv[0] = target; |
|
|
for (uint32_t i=0; i<len; i++) { |
|
|
for (uint32_t i=0; i<len; i++) { |
|
|
|
|
|
|
|
|
Handle<Function> cb = Handle<Function>::Cast( |
|
|
Handle<Function> cb = Handle<Function>::Cast( |
|
|
cont->callbacks->Get(Integer::New(i))); |
|
|
callbacks->Get(Integer::New(i))); |
|
|
|
|
|
|
|
|
TryCatch try_catch; |
|
|
TryCatch try_catch; |
|
|
|
|
|
|
|
@ -160,46 +179,45 @@ void TargetCallback(Isolate* isolate, Persistent<Object>* ptarget, void* arg) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
cont->proxy->SetAlignedPointerInInternalField(0, NULL); |
|
|
|
|
|
cont->proxy.Dispose(); |
|
|
cont->proxy.Dispose(); |
|
|
cont->proxy.Clear(); |
|
|
cont->proxy.Clear(); |
|
|
cont->target.Dispose(); |
|
|
cont->target.Dispose(); |
|
|
cont->target.Clear(); |
|
|
cont->target.Clear(); |
|
|
cont->callbacks.Dispose(); |
|
|
cont->callbacks.Dispose(); |
|
|
cont->callbacks.Clear(); |
|
|
cont->callbacks.Clear(); |
|
|
free(cont); |
|
|
delete cont; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> Create(const Arguments& args) { |
|
|
void Create(const FunctionCallbackInfo<Value>& args) { |
|
|
HandleScope scope; |
|
|
HandleScope scope; |
|
|
|
|
|
|
|
|
if (!args[0]->IsObject()) { |
|
|
if (!args[0]->IsObject()) { |
|
|
Local<String> message = String::New("Object expected"); |
|
|
Local<String> message = String::New("Object expected"); |
|
|
return ThrowException(Exception::TypeError(message)); |
|
|
ThrowException(Exception::TypeError(message)); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
proxy_container *cont = (proxy_container *) |
|
|
proxy_container *cont = new proxy_container; |
|
|
malloc(sizeof(proxy_container)); |
|
|
|
|
|
|
|
|
|
|
|
cont->target = Persistent<Object>::New(Isolate::GetCurrent(), |
|
|
Isolate* isolate = args.GetIsolate(); |
|
|
args[0]->ToObject()); |
|
|
Local<ObjectTemplate> tmpl = Local<ObjectTemplate>::New(isolate, proxyClass); |
|
|
cont->callbacks = Persistent<Array>::New(Isolate::GetCurrent(), |
|
|
Local<Object> proxy = tmpl->NewInstance(); |
|
|
Array::New()); |
|
|
proxy->SetAlignedPointerInInternalField(0, cont); |
|
|
|
|
|
|
|
|
cont->proxy = Persistent<Object>::New(Isolate::GetCurrent(), |
|
|
cont->proxy.Reset(Isolate::GetCurrent(), proxy); |
|
|
proxyClass->NewInstance()); |
|
|
cont->target.Reset(isolate, args[0].As<Object>()); |
|
|
cont->proxy->SetAlignedPointerInInternalField(0, cont); |
|
|
cont->callbacks.Reset(isolate, Array::New()); |
|
|
|
|
|
|
|
|
cont->target.MakeWeak(Isolate::GetCurrent(), |
|
|
cont->target.MakeWeak(Isolate::GetCurrent(), |
|
|
static_cast<void*>(cont), |
|
|
static_cast<void*>(cont), |
|
|
TargetCallback); |
|
|
TargetCallback); |
|
|
|
|
|
|
|
|
if (args.Length() >= 2) { |
|
|
if (args.Length() >= 2) { |
|
|
AddCallback(cont->proxy, Handle<Function>::Cast(args[1])); |
|
|
AddCallback(proxy, Handle<Function>::Cast(args[1])); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return cont->proxy; |
|
|
args.GetReturnValue().Set(proxy); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/**
|
|
|
/**
|
|
@ -210,102 +228,100 @@ bool isWeakRef (Handle<Value> val) { |
|
|
return val->IsObject() && val->ToObject()->InternalFieldCount() == 1; |
|
|
return val->IsObject() && val->ToObject()->InternalFieldCount() == 1; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Handle<Value> IsWeakRef (const Arguments& args) { |
|
|
void IsWeakRef (const FunctionCallbackInfo<Value>& args) { |
|
|
HandleScope scope; |
|
|
args.GetReturnValue().Set(isWeakRef(args[0])); |
|
|
return Boolean::New(isWeakRef(args[0])); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Handle<Value> Get(const Arguments& args) { |
|
|
void Get(const FunctionCallbackInfo<Value>& args) { |
|
|
HandleScope scope; |
|
|
HandleScope scope; |
|
|
|
|
|
|
|
|
if (!isWeakRef(args[0])) { |
|
|
if (!isWeakRef(args[0])) { |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
return ThrowException(Exception::TypeError(message)); |
|
|
ThrowException(Exception::TypeError(message)); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
|
|
|
|
|
|
|
|
|
const bool dead = IsDead(proxy); |
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
if (dead) return Undefined(); |
|
|
if (IsDead(proxy)) return; |
|
|
|
|
|
|
|
|
Handle<Object> obj = Unwrap(proxy); |
|
|
Handle<Object> obj = Unwrap(proxy); |
|
|
return scope.Close(obj); |
|
|
args.GetReturnValue().Set(obj); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Handle<Value> IsNearDeath(const Arguments& args) { |
|
|
void IsNearDeath(const FunctionCallbackInfo<Value>& args) { |
|
|
HandleScope scope; |
|
|
HandleScope scope; |
|
|
|
|
|
|
|
|
if (!isWeakRef(args[0])) { |
|
|
if (!isWeakRef(args[0])) { |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
return ThrowException(Exception::TypeError(message)); |
|
|
ThrowException(Exception::TypeError(message)); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
|
|
|
|
|
|
|
|
|
proxy_container *cont = reinterpret_cast<proxy_container*>( |
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
|
|
|
proxy_container *cont = static_cast<proxy_container*>( |
|
|
proxy->GetAlignedPointerFromInternalField(0)); |
|
|
proxy->GetAlignedPointerFromInternalField(0)); |
|
|
assert(cont != NULL); |
|
|
assert(cont != NULL); |
|
|
|
|
|
|
|
|
Handle<Boolean> rtn = Boolean::New(cont->target.IsNearDeath()); |
|
|
args.GetReturnValue().Set(cont->target.IsNearDeath()); |
|
|
|
|
|
|
|
|
return scope.Close(rtn); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Handle<Value> IsDead(const Arguments& args) { |
|
|
void IsDead(const FunctionCallbackInfo<Value>& args) { |
|
|
HandleScope scope; |
|
|
HandleScope scope; |
|
|
|
|
|
|
|
|
if (!isWeakRef(args[0])) { |
|
|
if (!isWeakRef(args[0])) { |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
return ThrowException(Exception::TypeError(message)); |
|
|
ThrowException(Exception::TypeError(message)); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
|
|
|
|
|
|
|
|
|
const bool dead = IsDead(proxy); |
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
return Boolean::New(dead); |
|
|
args.GetReturnValue().Set(IsDead(proxy)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Handle<Value> AddCallback(const Arguments& args) { |
|
|
void AddCallback(const FunctionCallbackInfo<Value>& args) { |
|
|
HandleScope scope; |
|
|
HandleScope scope; |
|
|
|
|
|
|
|
|
if (!isWeakRef(args[0])) { |
|
|
if (!isWeakRef(args[0])) { |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
return ThrowException(Exception::TypeError(message)); |
|
|
ThrowException(Exception::TypeError(message)); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
AddCallback(proxy, Handle<Function>::Cast(args[1])); |
|
|
AddCallback(proxy, Handle<Function>::Cast(args[1])); |
|
|
|
|
|
|
|
|
return Undefined(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
Handle<Value> Callbacks(const Arguments& args) { |
|
|
void Callbacks(const FunctionCallbackInfo<Value>& args) { |
|
|
HandleScope scope; |
|
|
HandleScope scope; |
|
|
|
|
|
|
|
|
if (!isWeakRef(args[0])) { |
|
|
if (!isWeakRef(args[0])) { |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
Local<String> message = String::New("Weakref instance expected"); |
|
|
return ThrowException(Exception::TypeError(message)); |
|
|
ThrowException(Exception::TypeError(message)); |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
|
|
|
|
|
|
|
|
|
return scope.Close(GetCallbacks(proxy)); |
|
|
Local<Object> proxy = args[0]->ToObject(); |
|
|
|
|
|
args.GetReturnValue().Set(GetCallbacks(proxy)); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Initialize(Handle<Object> target) { |
|
|
void Initialize(Handle<Object> target) { |
|
|
HandleScope scope; |
|
|
HandleScope scope; |
|
|
|
|
|
|
|
|
proxyClass = Persistent<ObjectTemplate>::New(Isolate::GetCurrent(), |
|
|
Local<ObjectTemplate> tmpl = ObjectTemplate::New(); |
|
|
ObjectTemplate::New()); |
|
|
tmpl->SetNamedPropertyHandler(WeakNamedPropertyGetter, |
|
|
proxyClass->SetNamedPropertyHandler(WeakNamedPropertyGetter, |
|
|
WeakNamedPropertySetter, |
|
|
WeakNamedPropertySetter, |
|
|
WeakNamedPropertyQuery, |
|
|
WeakNamedPropertyQuery, |
|
|
WeakNamedPropertyDeleter, |
|
|
WeakNamedPropertyDeleter, |
|
|
WeakPropertyEnumerator); |
|
|
WeakPropertyEnumerator); |
|
|
tmpl->SetIndexedPropertyHandler(WeakIndexedPropertyGetter, |
|
|
proxyClass->SetIndexedPropertyHandler(WeakIndexedPropertyGetter, |
|
|
WeakIndexedPropertySetter, |
|
|
WeakIndexedPropertySetter, |
|
|
WeakIndexedPropertyQuery, |
|
|
WeakIndexedPropertyQuery, |
|
|
WeakIndexedPropertyDeleter, |
|
|
WeakIndexedPropertyDeleter, |
|
|
WeakPropertyEnumerator); |
|
|
WeakPropertyEnumerator); |
|
|
tmpl->SetInternalFieldCount(1); |
|
|
proxyClass->SetInternalFieldCount(1); |
|
|
proxyClass.Reset(Isolate::GetCurrent(), tmpl); |
|
|
|
|
|
|
|
|
NODE_SET_METHOD(target, "get", Get); |
|
|
NODE_SET_METHOD(target, "get", Get); |
|
|
NODE_SET_METHOD(target, "create", Create); |
|
|
NODE_SET_METHOD(target, "create", Create); |
|
|