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())); |