Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: src/GlobalJsObject.cpp

Issue 29369365: Issue #4692 - Rewrite `SetTimeout` facility to avoid `JsValuePtr` and `JsValueList`
Patch Set: Created Dec. 19, 2016, 10:24 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/GlobalJsObject.h ('k') | src/JsContext.h » ('j') | src/JsEngine.cpp » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/GlobalJsObject.cpp
===================================================================
--- a/src/GlobalJsObject.cpp
+++ b/src/GlobalJsObject.cpp
@@ -25,6 +25,8 @@
#include "ConsoleJsObject.h"
#include "FileSystemJsObject.h"
#include "GlobalJsObject.h"
+#include "JsEngineInternal.h"
+#include "JsEngineTransition.h"
#include "Scheduler.h"
#include "Utils.h"
#include "WebRequestJsObject.h"
@@ -35,58 +37,95 @@
{
class TimeoutTask
{
+ typedef int64_t delayType; // return type of v8::Value::GetInteger()
public:
- TimeoutTask(JsValueList& arguments)
- {
- if (arguments.size() < 2)
- throw std::runtime_error("setTimeout requires at least 2 parameters");
-
- if (!arguments[0]->IsFunction())
- throw std::runtime_error(
- "First argument to setTimeout must be a function");
-
- function = arguments[0];
- delay = arguments[1]->AsInt();
- for (size_t i = 2; i < arguments.size(); i++)
- functionArguments.push_back(arguments[i]);
- }
+ TimeoutTask(
+ JsEngineInternal *engine,
+ V8PersistentNG<v8::Function> function,
+ delayType delay,
+ PersistentValueArray functionArguments
+ ) :
+ jsEnginePtr(engine->shared_from_this()),
+ function(function),
+ delay(delay),
+ functionArguments(std::move(functionArguments))
+ {}
void operator()()
- {
+ {
std::this_thread::sleep_for(std::chrono::milliseconds(delay));
- function->Call(functionArguments);
+
+ auto engine = ToInternal(jsEnginePtr);
+ V8ExecutionScope sentry(engine);
+ auto isolate = jsEnginePtr->GetIsolate();
+ engine->ApplyFunction(function.Get(isolate), functionArguments.GetAsLocal(isolate));
}
private:
- JsValuePtr function;
- int delay;
- JsValueList functionArguments;
+ /**
+ * shared_ptr ensures the engine remains in existence
+ * while we're waiting for the task to complete.
+ * The scheduler ought to undertake this responsibility,
+ * but until then we must do it ourselves.
+ */
+ AdblockPlus::JsEnginePtr jsEnginePtr;
Eric 2016/12/19 22:39:52 This is the only `JsEnginePtr` in the entirety of
+ V8PersistentNG<v8::Function> function;
+ delayType delay;
+ PersistentValueArray functionArguments;
};
+}
- v8::Handle<v8::Value> SetTimeoutCallback(const v8::Arguments& arguments)
+/**
+ * Callback function registered to v8 to implement `SetTimeout`
+ *
+ * Note that this implementation does not support the "evaluate code" version
+ * of `SetTimeout`, only the "apply function" version.
+ *
+ * \par Reference
+ * https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
+ */
+v8::Handle<v8::Value> CallbackForSetTimeout(const v8::Arguments& arguments)
+{
+ std::shared_ptr<TimeoutTask> timeoutTask;
+ auto engine = JsEngineInternal::ExtractEngine(arguments);
+ try
{
- std::shared_ptr<TimeoutTask> timeoutTask;
- JsEnginePtr engine;
- try
+ if (arguments.Length() < 2)
{
- engine = AdblockPlus::JsEngine::FromArguments(arguments);
- AdblockPlus::JsValueList converted =
- engine->ConvertArguments(arguments);
- timeoutTask = std::make_shared<TimeoutTask>(converted);
+ throw std::runtime_error("setTimeout: must have at least 2 arguments");
}
- catch (const std::exception& e)
+ if (!arguments[0]->IsFunction())
{
- v8::Isolate* isolate = arguments.GetIsolate();
- return v8::ThrowException(Utils::ToV8String(isolate, e.what()));
+ throw std::runtime_error("setTimeout: argument 1 must be a function");
}
- StartImmediatelyInSingleUseDetachedThread(MakeHeapFunction(timeoutTask));
+ auto isolate = engine->GetIsolate();
+ size_t n = arguments.Length() - 2;
+ PersistentValueArray functionArguments(n);
+ for (size_t i = 0; i < n; i++)
+ {
+ functionArguments[i] = V8PersistentNG<v8::Value>(isolate, arguments[i + 2]);
+ }
+ timeoutTask = std::make_shared<TimeoutTask>(
+ engine,
+ V8PersistentNG<v8::Function>(isolate, v8::Local<v8::Function>::Cast(arguments[0])),
+ arguments[1]->IntegerValue(),
+ std::move(functionArguments));
+ }
+ catch (const std::exception& e)
+ {
+ v8::Isolate* isolate = arguments.GetIsolate();
+ return v8::ThrowException(Utils::ToV8String(isolate, e.what()));
+ }
+ StartImmediatelyInSingleUseDetachedThread(MakeHeapFunction(timeoutTask));
- // We should actually return the timer ID here, which could be
- // used via clearTimeout(). But since we don't seem to need
- // clearTimeout(), we can save that for later.
- return v8::Undefined();
- }
+ // We should actually return the timer ID here, which could be
+ // used via clearTimeout(). But since we don't seem to need
+ // clearTimeout(), we can save that for later.
+ return v8::Undefined();
+}
+namespace
+{
v8::Handle<v8::Value> TriggerEventCallback(const v8::Arguments& arguments)
{
AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments);
@@ -104,10 +143,9 @@
}
}
-JsValuePtr GlobalJsObject::Setup(JsEnginePtr jsEngine, const AppInfo& appInfo,
+JsValuePtr AdblockPlus::GlobalJsObject::Setup(JsEnginePtr jsEngine, const AppInfo& appInfo,
JsValuePtr obj)
{
- obj->SetProperty("setTimeout", jsEngine->NewCallback(::SetTimeoutCallback));
Eric 2016/12/19 22:39:52 Old initialization of global object that used `JsE
obj->SetProperty("_triggerEvent", jsEngine->NewCallback(::TriggerEventCallback));
obj->SetProperty("_fileSystem",
FileSystemJsObject::Setup(jsEngine, jsEngine->NewObject()));
« no previous file with comments | « src/GlobalJsObject.h ('k') | src/JsContext.h » ('j') | src/JsEngine.cpp » ('J')

Powered by Google App Engine
This is Rietveld