| 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..004aaa329878f1e513ed91b00c603560d6662370 100644
|
| --- a/chrome/renderer/extensions/miscellaneous_bindings.cc
|
| +++ b/chrome/renderer/extensions/miscellaneous_bindings.cc
|
| @@ -9,7 +9,9 @@
|
|
|
| #include "base/basictypes.h"
|
| #include "base/bind.h"
|
| +#include "base/bind_helpers.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 +162,55 @@ 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.
|
| + class GCCallback {
|
| + public:
|
| + static void Bind(v8::Handle<v8::Object> object,
|
| + v8::Handle<v8::Function> callback) {
|
| + GCCallback* cb = new GCCallback(object, callback);
|
| + cb->object_.MakeWeak(cb, NearDeathCallback);
|
| + }
|
|
|
| private:
|
| - DISALLOW_COPY_AND_ASSIGN(GCCallbackArgs);
|
| - };
|
| + static void NearDeathCallback(v8::Isolate* isolate,
|
| + v8::Persistent<v8::Object>* object,
|
| + GCCallback* self) {
|
| + // v8 says we need to explicitly reset weak handles from their callbacks.
|
| + // It's not implicit as one might expect.
|
| + self->object_.reset();
|
| + base::MessageLoop::current()->PostTask(FROM_HERE,
|
| + base::Bind(&GCCallback::RunCallback, base::Owned(self)));
|
| + }
|
|
|
| - 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::Handle<v8::Object> object, v8::Handle<v8::Function> callback)
|
| + : object_(object), callback_(callback) {
|
| + }
|
| +
|
| + void RunCallback() {
|
| + v8::HandleScope handle_scope;
|
| + v8::Handle<v8::Context> context = callback_->CreationContext();
|
| + if (context.IsEmpty())
|
| + return;
|
| + v8::Context::Scope context_scope(context);
|
| + WebKit::WebScopedMicrotaskSuppression suppression;
|
| + 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);
|
| + GCCallback::Bind(args[0].As<v8::Object>(), args[1].As<v8::Function>());
|
| }
|
| };
|
|
|
|
|