|
| 1 | +#include "node_util.h" |
1 | 2 | #include "base_object-inl.h" |
2 | 3 | #include "node_errors.h" |
3 | 4 | #include "node_external_reference.h" |
@@ -15,7 +16,7 @@ using v8::Context; |
15 | 16 | using v8::External; |
16 | 17 | using v8::FunctionCallbackInfo; |
17 | 18 | using v8::FunctionTemplate; |
18 | | -using v8::Global; |
| 19 | +using v8::HandleScope; |
19 | 20 | using v8::IndexFilter; |
20 | 21 | using v8::Integer; |
21 | 22 | using v8::Isolate; |
@@ -207,52 +208,106 @@ void ArrayBufferViewHasBuffer(const FunctionCallbackInfo<Value>& args) { |
207 | 208 | args.GetReturnValue().Set(args[0].As<ArrayBufferView>()->HasBuffer()); |
208 | 209 | } |
209 | 210 |
|
210 | | -class WeakReference : public BaseObject { |
211 | | - public: |
212 | | - WeakReference(Environment* env, Local<Object> object, Local<Object> target) |
213 | | - : BaseObject(env, object) { |
214 | | - MakeWeak(); |
| 211 | +WeakReference::WeakReference(Environment* env, |
| 212 | + Local<Object> object, |
| 213 | + Local<Object> target) |
| 214 | + : WeakReference(env, object, target, 0) {} |
| 215 | + |
| 216 | +WeakReference::WeakReference(Environment* env, |
| 217 | + Local<Object> object, |
| 218 | + Local<Object> target, |
| 219 | + uint64_t reference_count) |
| 220 | + : SnapshotableObject(env, object, type_int), |
| 221 | + reference_count_(reference_count) { |
| 222 | + MakeWeak(); |
| 223 | + if (!target.IsEmpty()) { |
215 | 224 | target_.Reset(env->isolate(), target); |
216 | | - target_.SetWeak(); |
| 225 | + if (reference_count_ == 0) { |
| 226 | + target_.SetWeak(); |
| 227 | + } |
217 | 228 | } |
| 229 | +} |
218 | 230 |
|
219 | | - static void New(const FunctionCallbackInfo<Value>& args) { |
220 | | - Environment* env = Environment::GetCurrent(args); |
221 | | - CHECK(args.IsConstructCall()); |
222 | | - CHECK(args[0]->IsObject()); |
223 | | - new WeakReference(env, args.This(), args[0].As<Object>()); |
| 231 | +bool WeakReference::PrepareForSerialization(Local<Context> context, |
| 232 | + v8::SnapshotCreator* creator) { |
| 233 | + if (target_.IsEmpty()) { |
| 234 | + target_index_ = 0; |
| 235 | + return true; |
224 | 236 | } |
225 | 237 |
|
226 | | - static void Get(const FunctionCallbackInfo<Value>& args) { |
227 | | - WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder()); |
228 | | - Isolate* isolate = args.GetIsolate(); |
229 | | - if (!weak_ref->target_.IsEmpty()) |
230 | | - args.GetReturnValue().Set(weak_ref->target_.Get(isolate)); |
231 | | - } |
| 238 | + // Users can still hold strong references to target in addition to the |
| 239 | + // reference that we manage here, and they could expect that the referenced |
| 240 | + // object remains the same as long as that external strong reference |
| 241 | + // is alive. Since we have no way to know if there is any other reference |
| 242 | + // keeping the target alive, the best we can do to maintain consistency is to |
| 243 | + // simply save a reference to the target in the snapshot (effectively making |
| 244 | + // it strong) during serialization, and restore it during deserialization. |
| 245 | + // If there's no known counted reference from our side, we'll make the |
| 246 | + // reference here weak upon deserialization so that it can be GC'ed if users |
| 247 | + // do not hold additional references to it. |
| 248 | + Local<Object> target = target_.Get(context->GetIsolate()); |
| 249 | + target_index_ = creator->AddData(context, target); |
| 250 | + DCHECK_NE(target_index_, 0); |
| 251 | + target_.Reset(); |
| 252 | + return true; |
| 253 | +} |
232 | 254 |
|
233 | | - static void IncRef(const FunctionCallbackInfo<Value>& args) { |
234 | | - WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder()); |
235 | | - weak_ref->reference_count_++; |
236 | | - if (weak_ref->target_.IsEmpty()) return; |
237 | | - if (weak_ref->reference_count_ == 1) weak_ref->target_.ClearWeak(); |
238 | | - } |
| 255 | +InternalFieldInfoBase* WeakReference::Serialize(int index) { |
| 256 | + DCHECK_EQ(index, BaseObject::kEmbedderType); |
| 257 | + InternalFieldInfo* info = |
| 258 | + InternalFieldInfoBase::New<InternalFieldInfo>(type()); |
| 259 | + info->target = target_index_; |
| 260 | + info->reference_count = reference_count_; |
| 261 | + return info; |
| 262 | +} |
239 | 263 |
|
240 | | - static void DecRef(const FunctionCallbackInfo<Value>& args) { |
241 | | - WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder()); |
242 | | - CHECK_GE(weak_ref->reference_count_, 1); |
243 | | - weak_ref->reference_count_--; |
244 | | - if (weak_ref->target_.IsEmpty()) return; |
245 | | - if (weak_ref->reference_count_ == 0) weak_ref->target_.SetWeak(); |
| 264 | +void WeakReference::Deserialize(Local<Context> context, |
| 265 | + Local<Object> holder, |
| 266 | + int index, |
| 267 | + InternalFieldInfoBase* info) { |
| 268 | + DCHECK_EQ(index, BaseObject::kEmbedderType); |
| 269 | + HandleScope scope(context->GetIsolate()); |
| 270 | + |
| 271 | + InternalFieldInfo* weak_info = reinterpret_cast<InternalFieldInfo*>(info); |
| 272 | + Local<Object> target; |
| 273 | + if (weak_info->target != 0) { |
| 274 | + target = context->GetDataFromSnapshotOnce<Object>(weak_info->target) |
| 275 | + .ToLocalChecked(); |
246 | 276 | } |
| 277 | + new WeakReference(Environment::GetCurrent(context), |
| 278 | + holder, |
| 279 | + target, |
| 280 | + weak_info->reference_count); |
| 281 | +} |
| 282 | + |
| 283 | +void WeakReference::New(const FunctionCallbackInfo<Value>& args) { |
| 284 | + Environment* env = Environment::GetCurrent(args); |
| 285 | + CHECK(args.IsConstructCall()); |
| 286 | + CHECK(args[0]->IsObject()); |
| 287 | + new WeakReference(env, args.This(), args[0].As<Object>()); |
| 288 | +} |
| 289 | + |
| 290 | +void WeakReference::Get(const FunctionCallbackInfo<Value>& args) { |
| 291 | + WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder()); |
| 292 | + Isolate* isolate = args.GetIsolate(); |
| 293 | + if (!weak_ref->target_.IsEmpty()) |
| 294 | + args.GetReturnValue().Set(weak_ref->target_.Get(isolate)); |
| 295 | +} |
247 | 296 |
|
248 | | - SET_MEMORY_INFO_NAME(WeakReference) |
249 | | - SET_SELF_SIZE(WeakReference) |
250 | | - SET_NO_MEMORY_INFO() |
| 297 | +void WeakReference::IncRef(const FunctionCallbackInfo<Value>& args) { |
| 298 | + WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder()); |
| 299 | + weak_ref->reference_count_++; |
| 300 | + if (weak_ref->target_.IsEmpty()) return; |
| 301 | + if (weak_ref->reference_count_ == 1) weak_ref->target_.ClearWeak(); |
| 302 | +} |
251 | 303 |
|
252 | | - private: |
253 | | - Global<Object> target_; |
254 | | - uint64_t reference_count_ = 0; |
255 | | -}; |
| 304 | +void WeakReference::DecRef(const FunctionCallbackInfo<Value>& args) { |
| 305 | + WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder()); |
| 306 | + CHECK_GE(weak_ref->reference_count_, 1); |
| 307 | + weak_ref->reference_count_--; |
| 308 | + if (weak_ref->target_.IsEmpty()) return; |
| 309 | + if (weak_ref->reference_count_ == 0) weak_ref->target_.SetWeak(); |
| 310 | +} |
256 | 311 |
|
257 | 312 | static void GuessHandleType(const FunctionCallbackInfo<Value>& args) { |
258 | 313 | Environment* env = Environment::GetCurrent(args); |
|