-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
Fix a regression that was introduced in commit ce04c72 after the upgrade to V8 3.24. The new weak persistent handle API no longer gives you the original persistent but still requires that you clear it inside your weak callback. Rearrange the code in src/smalloc.cc to keep track of the persistent handle with the least amount of pain and try hard to share as much code as possible between the 'just free it' and 'invoke my callback' versions of the smalloc API. Fixes nodejs#7309.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,17 +54,148 @@ using v8::WeakCallbackData; | |
using v8::kExternalUnsignedByteArray; | ||
|
||
|
||
struct CallbackInfo { | ||
void* hint; | ||
FreeCallback cb; | ||
Persistent<Object> p_obj; | ||
template <typename Payload> | ||
class CallbackInfo { | ||
public: | ||
static inline CallbackInfo* New(Isolate* isolate, | ||
Handle<Object> object, | ||
Payload payload); | ||
inline void Dispose(); | ||
inline Persistent<Object>* persistent(); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
bnoordhuis
Author
Owner
|
||
inline Payload* payload(); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
private: | ||
static void WeakCallback(const WeakCallbackData<Object, CallbackInfo>&); | ||
inline CallbackInfo(Isolate* isolate, | ||
Handle<Object> object, | ||
Payload payload); | ||
~CallbackInfo(); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
Persistent<Object> persistent_; | ||
Payload payload_; | ||
}; | ||
|
||
void TargetCallback(const WeakCallbackData<Object, char>& data); | ||
void TargetFreeCallback(Isolate* isolate, | ||
Persistent<Object>* target, | ||
CallbackInfo* cb_info); | ||
void TargetFreeCallback(const WeakCallbackData<Object, CallbackInfo>& data); | ||
|
||
class Free { | ||
public: | ||
explicit Free(char* data); | ||
void WeakCallback(Isolate* isolate, | ||
Local<Object> object, | ||
CallbackInfo<Free>* info); | ||
private: | ||
char* const data_; | ||
}; | ||
|
||
|
||
class Dispose { | ||
public: | ||
typedef void (*Callback)(char* data, void* hint); | ||
Dispose(Callback callback, void* hint); | ||
void WeakCallback(Isolate* isolate, | ||
Local<Object> object, | ||
CallbackInfo<Dispose>* info); | ||
private: | ||
Callback const callback_; | ||
void* const hint_; | ||
}; | ||
|
||
|
||
template <typename Payload> | ||
CallbackInfo<Payload>* CallbackInfo<Payload>::New(Isolate* isolate, | ||
Handle<Object> object, | ||
Payload payload) { | ||
return new CallbackInfo(isolate, object, payload); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
} | ||
|
||
|
||
template <typename Payload> | ||
void CallbackInfo<Payload>::Dispose() { | ||
delete this; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong. |
||
} | ||
|
||
|
||
template <typename Payload> | ||
Persistent<Object>* CallbackInfo<Payload>::persistent() { | ||
return &persistent_; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
bnoordhuis
Author
Owner
|
||
} | ||
|
||
|
||
template <typename Payload> | ||
Payload* CallbackInfo<Payload>::payload() { | ||
return &payload_; | ||
This comment has been minimized.
Sorry, something went wrong. |
||
} | ||
|
||
|
||
template <typename Payload> | ||
CallbackInfo<Payload>::CallbackInfo(Isolate* isolate, | ||
Handle<Object> object, | ||
Payload payload) | ||
: persistent_(isolate, object), | ||
payload_(payload) { | ||
persistent_.SetWeak(this, WeakCallback); | ||
persistent_.SetWrapperClassId(ALLOC_ID); | ||
persistent_.MarkIndependent(); | ||
} | ||
|
||
|
||
template <typename Payload> | ||
CallbackInfo<Payload>::~CallbackInfo() { | ||
persistent_.Reset(); | ||
} | ||
|
||
|
||
template <typename Payload> | ||
void CallbackInfo<Payload>::WeakCallback( | ||
const WeakCallbackData<Object, CallbackInfo>& data) { | ||
CallbackInfo* info = data.GetParameter(); | ||
info->payload()->WeakCallback(data.GetIsolate(), data.GetValue(), info); | ||
} | ||
|
||
|
||
Free::Free(char* data) : data_(data) { | ||
This comment has been minimized.
Sorry, something went wrong. |
||
} | ||
|
||
|
||
void Free::WeakCallback(Isolate* isolate, | ||
Local<Object> object, | ||
CallbackInfo<Free>* info) { | ||
free(data_); | ||
size_t length = object->GetIndexedPropertiesExternalArrayDataLength(); | ||
enum ExternalArrayType array_type = | ||
object->GetIndexedPropertiesExternalArrayDataType(); | ||
size_t array_size = ExternalArraySize(array_type); | ||
CHECK_GT(array_size, 0); | ||
CHECK_GE(array_size * length, length); // Overflow check. | ||
length *= array_size; | ||
int64_t change_in_bytes = -static_cast<int64_t>(length); | ||
isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes); | ||
info->Dispose(); | ||
} | ||
|
||
|
||
Dispose::Dispose(Callback callback, void* hint) | ||
This comment has been minimized.
Sorry, something went wrong. |
||
: callback_(callback), | ||
hint_(hint) { | ||
} | ||
|
||
|
||
void Dispose::WeakCallback(Isolate* isolate, | ||
Local<Object> object, | ||
CallbackInfo<Dispose>* info) { | ||
char* data = | ||
static_cast<char*>(object->GetIndexedPropertiesExternalArrayData()); | ||
size_t len = object->GetIndexedPropertiesExternalArrayDataLength(); | ||
enum ExternalArrayType array_type = | ||
object->GetIndexedPropertiesExternalArrayDataType(); | ||
size_t array_size = ExternalArraySize(array_type); | ||
CHECK_GT(array_size, 0); | ||
if (array_size > 1) { | ||
CHECK_GT(len * array_size, len); // Overflow check. | ||
len *= array_size; | ||
} | ||
int64_t change_in_bytes = -static_cast<int64_t>(len + sizeof(*info)); | ||
isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes); | ||
callback_(data, hint_); | ||
info->Dispose(); | ||
} | ||
|
||
|
||
// return size of external array type, or 0 if unrecognized | ||
|
@@ -268,36 +399,10 @@ void Alloc(Environment* env, | |
size_t length, | ||
enum ExternalArrayType type) { | ||
assert(!obj->HasIndexedPropertiesInExternalArrayData()); | ||
Persistent<Object> p_obj(env->isolate(), obj); | ||
env->isolate()->AdjustAmountOfExternalAllocatedMemory(length); | ||
p_obj.SetWeak(data, TargetCallback); | ||
p_obj.MarkIndependent(); | ||
p_obj.SetWrapperClassId(ALLOC_ID); | ||
size_t size = length / ExternalArraySize(type); | ||
obj->SetIndexedPropertiesToExternalArrayData(data, type, size); | ||
} | ||
|
||
|
||
void TargetCallback(const WeakCallbackData<Object, char>& data) { | ||
HandleScope handle_scope(data.GetIsolate()); | ||
char* info = data.GetParameter(); | ||
|
||
Local<Object> obj = data.GetValue(); | ||
size_t len = obj->GetIndexedPropertiesExternalArrayDataLength(); | ||
enum ExternalArrayType array_type = | ||
obj->GetIndexedPropertiesExternalArrayDataType(); | ||
size_t array_size = ExternalArraySize(array_type); | ||
assert(array_size > 0); | ||
assert(array_size * len >= len); | ||
len *= array_size; | ||
if (info != NULL && len > 0) { | ||
int64_t change_in_bytes = -static_cast<int64_t>(len); | ||
data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(change_in_bytes); | ||
free(info); | ||
} | ||
|
||
// XXX: Persistent is no longer passed here | ||
// persistent.Reset(); | ||
CallbackInfo<Free>::New(env->isolate(), obj, Free(data)); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
} | ||
|
||
|
||
|
@@ -315,8 +420,10 @@ void AllocDispose(Environment* env, Handle<Object> obj) { | |
Local<Value> ext_v = obj->GetHiddenValue(env->smalloc_p_string()); | ||
if (ext_v->IsExternal()) { | ||
Local<External> ext = ext_v.As<External>(); | ||
CallbackInfo* cb_info = static_cast<CallbackInfo*>(ext->Value()); | ||
TargetFreeCallback(env->isolate(), &cb_info->p_obj, cb_info); | ||
CallbackInfo<Free>* info = static_cast<CallbackInfo<Free>*>(ext->Value()); | ||
Local<Object> object = PersistentToLocal(env->isolate(), | ||
*info->persistent()); | ||
info->payload()->WeakCallback(env->isolate(), object, info); | ||
return; | ||
} | ||
} | ||
|
@@ -373,56 +480,18 @@ void Alloc(Environment* env, | |
void* hint, | ||
enum ExternalArrayType type) { | ||
assert(!obj->HasIndexedPropertiesInExternalArrayData()); | ||
|
||
HandleScope handle_scope(env->isolate()); | ||
Isolate* isolate = env->isolate(); | ||
HandleScope handle_scope(isolate); | ||
env->set_using_smalloc_alloc_cb(true); | ||
|
||
CallbackInfo* cb_info = new CallbackInfo; | ||
cb_info->cb = fn; | ||
cb_info->hint = hint; | ||
cb_info->p_obj.Reset(env->isolate(), obj); | ||
obj->SetHiddenValue(env->smalloc_p_string(), | ||
External::New(env->isolate(), cb_info)); | ||
|
||
env->isolate()->AdjustAmountOfExternalAllocatedMemory(length + | ||
sizeof(*cb_info)); | ||
cb_info->p_obj.SetWeak(cb_info, TargetFreeCallback); | ||
cb_info->p_obj.MarkIndependent(); | ||
cb_info->p_obj.SetWrapperClassId(ALLOC_ID); | ||
CallbackInfo<Dispose>* info = | ||
CallbackInfo<Dispose>::New(isolate, obj, Dispose(fn, hint)); | ||
obj->SetHiddenValue(env->smalloc_p_string(), External::New(isolate, info)); | ||
isolate->AdjustAmountOfExternalAllocatedMemory(length + sizeof(*info)); | ||
size_t size = length / ExternalArraySize(type); | ||
obj->SetIndexedPropertiesToExternalArrayData(data, type, size); | ||
} | ||
|
||
|
||
void TargetFreeCallback(Isolate* isolate, | ||
Persistent<Object>* target, | ||
CallbackInfo* cb_info) { | ||
HandleScope handle_scope(isolate); | ||
Local<Object> obj = PersistentToLocal(isolate, *target); | ||
char* data = static_cast<char*>(obj->GetIndexedPropertiesExternalArrayData()); | ||
size_t len = obj->GetIndexedPropertiesExternalArrayDataLength(); | ||
enum ExternalArrayType array_type = | ||
obj->GetIndexedPropertiesExternalArrayDataType(); | ||
size_t array_size = ExternalArraySize(array_type); | ||
assert(array_size > 0); | ||
if (array_size > 1) { | ||
assert(len * array_size > len); | ||
len *= array_size; | ||
} | ||
int64_t change_in_bytes = -static_cast<int64_t>(len + sizeof(*cb_info)); | ||
isolate->AdjustAmountOfExternalAllocatedMemory(change_in_bytes); | ||
cb_info->p_obj.Reset(); | ||
cb_info->cb(data, cb_info->hint); | ||
delete cb_info; | ||
} | ||
|
||
|
||
void TargetFreeCallback(const WeakCallbackData<Object, CallbackInfo>& data) { | ||
CallbackInfo* cb_info = data.GetParameter(); | ||
TargetFreeCallback(data.GetIsolate(), &cb_info->p_obj, cb_info); | ||
} | ||
|
||
|
||
void HasExternalData(const FunctionCallbackInfo<Value>& args) { | ||
Environment* env = Environment::GetCurrent(args.GetIsolate()); | ||
args.GetReturnValue().Set(args[0]->IsObject() && | ||
|
2 comments
on commit 5bfb0de
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm... Actually, I thought that I have fixed it myself. Perhaps it was lost somewhere in rebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, LGTM
I guess it could be
inline Persistent<Object>* persistent() const
?