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

Side by Side 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.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2016 Eyeo GmbH 3 * Copyright (C) 2006-2016 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #include <stdexcept> 18 #include <stdexcept>
19 #include <thread> 19 #include <thread>
20 #include <vector> 20 #include <vector>
21 21
22 #include <AdblockPlus/JsValue.h> 22 #include <AdblockPlus/JsValue.h>
23 23
24 #include "AppInfoJsObject.h" 24 #include "AppInfoJsObject.h"
25 #include "ConsoleJsObject.h" 25 #include "ConsoleJsObject.h"
26 #include "FileSystemJsObject.h" 26 #include "FileSystemJsObject.h"
27 #include "GlobalJsObject.h" 27 #include "GlobalJsObject.h"
28 #include "JsEngineInternal.h"
29 #include "JsEngineTransition.h"
28 #include "Scheduler.h" 30 #include "Scheduler.h"
29 #include "Utils.h" 31 #include "Utils.h"
30 #include "WebRequestJsObject.h" 32 #include "WebRequestJsObject.h"
31 33
32 using namespace AdblockPlus; 34 using namespace AdblockPlus;
33 35
34 namespace 36 namespace
35 { 37 {
36 class TimeoutTask 38 class TimeoutTask
37 { 39 {
40 typedef int64_t delayType; // return type of v8::Value::GetInteger()
38 public: 41 public:
39 TimeoutTask(JsValueList& arguments) 42 TimeoutTask(
40 { 43 JsEngineInternal *engine,
41 if (arguments.size() < 2) 44 V8PersistentNG<v8::Function> function,
42 throw std::runtime_error("setTimeout requires at least 2 parameters"); 45 delayType delay,
43 46 PersistentValueArray functionArguments
44 if (!arguments[0]->IsFunction()) 47 ) :
45 throw std::runtime_error( 48 jsEnginePtr(engine->shared_from_this()),
46 "First argument to setTimeout must be a function"); 49 function(function),
47 50 delay(delay),
48 function = arguments[0]; 51 functionArguments(std::move(functionArguments))
49 delay = arguments[1]->AsInt(); 52 {}
50 for (size_t i = 2; i < arguments.size(); i++)
51 functionArguments.push_back(arguments[i]);
52 }
53 53
54 void operator()() 54 void operator()()
55 { 55 {
56 std::this_thread::sleep_for(std::chrono::milliseconds(delay)); 56 std::this_thread::sleep_for(std::chrono::milliseconds(delay));
57 function->Call(functionArguments); 57
58 auto engine = ToInternal(jsEnginePtr);
59 V8ExecutionScope sentry(engine);
60 auto isolate = jsEnginePtr->GetIsolate();
61 engine->ApplyFunction(function.Get(isolate), functionArguments.GetAsLocal( isolate));
58 } 62 }
59 63
60 private: 64 private:
61 JsValuePtr function; 65 /**
62 int delay; 66 * shared_ptr ensures the engine remains in existence
63 JsValueList functionArguments; 67 * while we're waiting for the task to complete.
68 * The scheduler ought to undertake this responsibility,
69 * but until then we must do it ourselves.
70 */
71 AdblockPlus::JsEnginePtr jsEnginePtr;
Eric 2016/12/19 22:39:52 This is the only `JsEnginePtr` in the entirety of
72 V8PersistentNG<v8::Function> function;
73 delayType delay;
74 PersistentValueArray functionArguments;
64 }; 75 };
76 }
65 77
66 v8::Handle<v8::Value> SetTimeoutCallback(const v8::Arguments& arguments) 78 /**
79 * Callback function registered to v8 to implement `SetTimeout`
80 *
81 * Note that this implementation does not support the "evaluate code" version
82 * of `SetTimeout`, only the "apply function" version.
83 *
84 * \par Reference
85 * https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout
86 */
87 v8::Handle<v8::Value> CallbackForSetTimeout(const v8::Arguments& arguments)
88 {
89 std::shared_ptr<TimeoutTask> timeoutTask;
90 auto engine = JsEngineInternal::ExtractEngine(arguments);
91 try
67 { 92 {
68 std::shared_ptr<TimeoutTask> timeoutTask; 93 if (arguments.Length() < 2)
69 JsEnginePtr engine;
70 try
71 { 94 {
72 engine = AdblockPlus::JsEngine::FromArguments(arguments); 95 throw std::runtime_error("setTimeout: must have at least 2 arguments");
73 AdblockPlus::JsValueList converted =
74 engine->ConvertArguments(arguments);
75 timeoutTask = std::make_shared<TimeoutTask>(converted);
76 } 96 }
77 catch (const std::exception& e) 97 if (!arguments[0]->IsFunction())
78 { 98 {
79 v8::Isolate* isolate = arguments.GetIsolate(); 99 throw std::runtime_error("setTimeout: argument 1 must be a function");
80 return v8::ThrowException(Utils::ToV8String(isolate, e.what()));
81 } 100 }
82 StartImmediatelyInSingleUseDetachedThread(MakeHeapFunction(timeoutTask)); 101 auto isolate = engine->GetIsolate();
102 size_t n = arguments.Length() - 2;
103 PersistentValueArray functionArguments(n);
104 for (size_t i = 0; i < n; i++)
105 {
106 functionArguments[i] = V8PersistentNG<v8::Value>(isolate, arguments[i + 2] );
107 }
108 timeoutTask = std::make_shared<TimeoutTask>(
109 engine,
110 V8PersistentNG<v8::Function>(isolate, v8::Local<v8::Function>::Cast(argume nts[0])),
111 arguments[1]->IntegerValue(),
112 std::move(functionArguments));
113 }
114 catch (const std::exception& e)
115 {
116 v8::Isolate* isolate = arguments.GetIsolate();
117 return v8::ThrowException(Utils::ToV8String(isolate, e.what()));
118 }
119 StartImmediatelyInSingleUseDetachedThread(MakeHeapFunction(timeoutTask));
83 120
84 // We should actually return the timer ID here, which could be 121 // We should actually return the timer ID here, which could be
85 // used via clearTimeout(). But since we don't seem to need 122 // used via clearTimeout(). But since we don't seem to need
86 // clearTimeout(), we can save that for later. 123 // clearTimeout(), we can save that for later.
87 return v8::Undefined(); 124 return v8::Undefined();
88 } 125 }
89 126
127 namespace
128 {
90 v8::Handle<v8::Value> TriggerEventCallback(const v8::Arguments& arguments) 129 v8::Handle<v8::Value> TriggerEventCallback(const v8::Arguments& arguments)
91 { 130 {
92 AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arg uments); 131 AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arg uments);
93 AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); 132 AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments);
94 if (converted.size() < 1) 133 if (converted.size() < 1)
95 { 134 {
96 v8::Isolate* isolate = arguments.GetIsolate(); 135 v8::Isolate* isolate = arguments.GetIsolate();
97 return v8::ThrowException(Utils::ToV8String(isolate, 136 return v8::ThrowException(Utils::ToV8String(isolate,
98 "_triggerEvent expects at least one parameter")); 137 "_triggerEvent expects at least one parameter"));
99 } 138 }
100 std::string eventName = converted.front()->AsString(); 139 std::string eventName = converted.front()->AsString();
101 converted.erase(converted.begin()); 140 converted.erase(converted.begin());
102 jsEngine->TriggerEvent(eventName, converted); 141 jsEngine->TriggerEvent(eventName, converted);
103 return v8::Undefined(); 142 return v8::Undefined();
104 } 143 }
105 } 144 }
106 145
107 JsValuePtr GlobalJsObject::Setup(JsEnginePtr jsEngine, const AppInfo& appInfo, 146 JsValuePtr AdblockPlus::GlobalJsObject::Setup(JsEnginePtr jsEngine, const AppInf o& appInfo,
108 JsValuePtr obj) 147 JsValuePtr obj)
109 { 148 {
110 obj->SetProperty("setTimeout", jsEngine->NewCallback(::SetTimeoutCallback));
Eric 2016/12/19 22:39:52 Old initialization of global object that used `JsE
111 obj->SetProperty("_triggerEvent", jsEngine->NewCallback(::TriggerEventCallback )); 149 obj->SetProperty("_triggerEvent", jsEngine->NewCallback(::TriggerEventCallback ));
112 obj->SetProperty("_fileSystem", 150 obj->SetProperty("_fileSystem",
113 FileSystemJsObject::Setup(jsEngine, jsEngine->NewObject())); 151 FileSystemJsObject::Setup(jsEngine, jsEngine->NewObject()));
114 obj->SetProperty("_webRequest", 152 obj->SetProperty("_webRequest",
115 WebRequestJsObject::Setup(jsEngine, jsEngine->NewObject())); 153 WebRequestJsObject::Setup(jsEngine, jsEngine->NewObject()));
116 obj->SetProperty("console", 154 obj->SetProperty("console",
117 ConsoleJsObject::Setup(jsEngine, jsEngine->NewObject())); 155 ConsoleJsObject::Setup(jsEngine, jsEngine->NewObject()));
118 obj->SetProperty("_appInfo", 156 obj->SetProperty("_appInfo",
119 AppInfoJsObject::Setup(jsEngine, appInfo, jsEngine->NewObject())); 157 AppInfoJsObject::Setup(jsEngine, appInfo, jsEngine->NewObject()));
120 return obj; 158 return obj;
121 } 159 }
OLDNEW
« 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