Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8278)

Unified Diff: chrome/renderer/extensions/miscellaneous_bindings.cc

Issue 19670020: Run the Port cleanup code inside BindToGC in a setTimeout call to avoid (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: use message loop Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/renderer/extensions/miscellaneous_bindings.cc
diff --git a/chrome/renderer/extensions/miscellaneous_bindings.cc b/chrome/renderer/extensions/miscellaneous_bindings.cc
index 8921d77ea680f16736049a7b2083a1ccf6447230..1f70a5bc76617d7e5c06109f9aae3c4fb3200957 100644
--- a/chrome/renderer/extensions/miscellaneous_bindings.cc
+++ b/chrome/renderer/extensions/miscellaneous_bindings.cc
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/lazy_instance.h"
+#include "base/message_loop/message_loop.h"
#include "base/values.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/message_bundle.h"
@@ -160,39 +161,53 @@ class ExtensionImpl : public extensions::ChromeV8Extension {
}
}
- struct GCCallbackArgs {
- GCCallbackArgs(v8::Handle<v8::Object> object,
- v8::Handle<v8::Function> callback)
- : object(object), callback(callback) {}
-
- extensions::ScopedPersistent<v8::Object> object;
- extensions::ScopedPersistent<v8::Function> callback;
+ // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will
+ // not be executed re-entrantly to avoid running JS in an unexpected state.
+ //
+ // Bound to the lifetime of |object|.
+ class GCCallback {
+ public:
+ GCCallback(v8::Handle<v8::Object> object, v8::Handle<v8::Function> callback)
+ : object_(object), callback_(callback) {
+ object_.MakeWeak(this, NearDeathCallback);
+ }
private:
- DISALLOW_COPY_AND_ASSIGN(GCCallbackArgs);
- };
+ friend class base::DeleteHelper<GCCallback>;
+
+ static void NearDeathCallback(v8::Isolate* isolate,
+ v8::Persistent<v8::Object>* object,
+ GCCallback* self) {
adamk 2013/07/23 22:47:38 I think you want to call self->object_.reset() h
not at google - send to devlin 2013/07/23 22:55:04 ah good point.
Jeffrey Yasskin 2013/07/23 22:59:35 And possibly link to https://code.google.com/p/chr
not at google - send to devlin 2013/07/23 23:17:41 Added comment (though not to the source itself, ar
+ // Delete this and execute function in destructor to be safe across
+ // message loop shutdown and avoid leaking any v8 state.
+ base::MessageLoop::current()->DeleteSoon(FROM_HERE, self);
Jeffrey Yasskin 2013/07/23 22:59:35 I'd just PostTask(Bind(&GCCallback::DoStuff, Owned
Jeffrey Yasskin 2013/07/23 22:59:35 After posting to the MessageLoop, how do we know t
not at google - send to devlin 2013/07/23 23:17:41 Done.
not at google - send to devlin 2013/07/23 23:17:41 callback_ is Persistent, so it will "by definition
adamk 2013/07/23 23:43:21 All the entry points check for a dead Isolate befo
+ }
- static void GCCallback(v8::Isolate* isolate,
- v8::Persistent<v8::Object>* object,
- GCCallbackArgs* args) {
- v8::HandleScope handle_scope;
- v8::Handle<v8::Context> context = args->callback->CreationContext();
- v8::Context::Scope context_scope(context);
- WebKit::WebScopedMicrotaskSuppression suppression;
- // Wrap in try/catch here so that we don't call into any message/exception
- // handlers during GC. That is a recipe for pain.
- v8::TryCatch trycatch;
- args->callback->Call(context->Global(), 0, NULL);
- delete args;
- }
+ ~GCCallback() {
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Context> context = callback_->CreationContext();
adamk 2013/07/23 23:43:21 ...except that this Handle will be empty if the is
+ v8::Context::Scope context_scope(context);
+ WebKit::WebScopedMicrotaskSuppression suppression;
+ // Wrap in try/catch here so that we don't call into any message/exception
+ // handlers during GC. That is a recipe for pain.
+ v8::TryCatch trycatch;
+ callback_->Call(context->Global(), 0, NULL);
+ }
+
+ extensions::ScopedPersistent<v8::Object> object_;
+ extensions::ScopedPersistent<v8::Function> callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(GCCallback);
+ };
- // Binds a callback to be invoked when the given object is garbage collected.
+ // void BindToGC(object, callback)
+ //
+ // Binds |callback| to be invoked *sometime after* |object| is garbage
+ // collected. We don't call the method re-entrantly so as to avoid executing
+ // JS in some bizarro undefined mid-GC state.
void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) {
CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction());
- GCCallbackArgs* context = new GCCallbackArgs(
- v8::Handle<v8::Object>::Cast(args[0]),
- v8::Handle<v8::Function>::Cast(args[1]));
- context->object.MakeWeak(context, GCCallback);
+ new GCCallback(args[0].As<v8::Object>(), args[1].As<v8::Function>());
Jeffrey Yasskin 2013/07/23 22:59:35 If possible, I'd rather not have code that looks l
}
};
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698