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

Side by Side Diff: src/JsEngine.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 <AdblockPlus.h> 18 #include <AdblockPlus.h>
19 #include "GlobalJsObject.h" 19 #include "GlobalJsObject.h"
20 #include "JsContext.h" 20 #include "JsContext.h"
21 #include "JsEngineInternal.h"
22 #include "JsEngineTransition.h"
21 #include "JsError.h" 23 #include "JsError.h"
22 #include "Scheduler.h" 24 #include "Scheduler.h"
23 #include "Utils.h" 25 #include "Utils.h"
24 26
25 const AdblockPlus::ImmediateSingleUseThreadType AdblockPlus::ImmediateSingleUseT hread = {}; 27 const AdblockPlus::ImmediateSingleUseThreadType AdblockPlus::ImmediateSingleUseT hread = {};
26 28
27 class AdblockPlus::JsEngine::SchedulerImpl 29 class AdblockPlus::JsEngine::SchedulerImpl
28 : public SchedulerT<SingleUseWorker> 30 : public SchedulerT<SingleUseWorker>
29 { 31 {
30 public: 32 public:
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 public: 69 public:
68 static void Init() 70 static void Init()
69 { 71 {
70 // it's threadsafe since C++11 and it will be instantiated only once and 72 // it's threadsafe since C++11 and it will be instantiated only once and
71 // destroyed at the application exit 73 // destroyed at the application exit
72 static V8Initializer initializer; 74 static V8Initializer initializer;
73 } 75 }
74 }; 76 };
75 } 77 }
76 78
79 V8ExecutionScope::V8ExecutionScope(JsEngineInternal* engine)
80 : lock(engine->GetIsolate()),
81 isolateScope(engine->GetIsolate()),
82 handleScope(engine->GetIsolate()),
83 contextScope(engine->GetContextAsLocal())
84 {}
85
77 AdblockPlus::ScopedV8Isolate::ScopedV8Isolate() 86 AdblockPlus::ScopedV8Isolate::ScopedV8Isolate()
78 { 87 {
79 V8Initializer::Init(); 88 V8Initializer::Init();
80 isolate = v8::Isolate::New(); 89 isolate = v8::Isolate::New();
81 } 90 }
82 91
83 AdblockPlus::ScopedV8Isolate::~ScopedV8Isolate() 92 AdblockPlus::ScopedV8Isolate::~ScopedV8Isolate()
84 { 93 {
85 isolate->Dispose(); 94 isolate->Dispose();
86 isolate = nullptr; 95 isolate = nullptr;
87 } 96 }
88 97
89 AdblockPlus::JsEngine::JsEngine(const ScopedV8IsolatePtr& isolate) 98 AdblockPlus::JsEngine::JsEngine(const ScopedV8IsolatePtr& isolate)
90 : isolate(isolate), 99 : isolate(isolate),
91 scheduler(new SchedulerImpl()) // use std::make_unique after we upgrade out of VS2012 100 scheduler(new SchedulerImpl()) // TODO: make_unique once available
92 {} 101 {}
93 102
103 JsEngineInternal::JsEngineInternal(const AdblockPlus::ScopedV8IsolatePtr& isolat e)
104 : AdblockPlus::JsEngine(isolate),
105 context(isolate->Get(),v8::Context::New(isolate->Get()))
106 {
107 /*
108 * Enter v8 scope for our context so that we can initialize its global object.
109 */
110 const v8::Context::Scope contextScope(GetContextAsLocal());
111 auto globalObject = GetGlobalObject();
112 auto propertyName = AdblockPlus::Utils::ToV8String(GetIsolate(), "setTimeout") ;
113 globalObject->Set(propertyName, MakeCallback(::CallbackForSetTimeout));
Eric 2016/12/19 22:39:53 New initialization of global object without any us
114 // TODO: Move the rest of the global object initializations here
115 }
116
117 /**
118 * \par Design Notes
119 * It is technically necessary to construct JsEngine instances *only* within a f actory.
120 * Initialization requires that certain transient v8 scopes be set up
121 * before initialization and torn down afterwards.
122 * C++ has no syntax to use anything like a sentry object in the constructor its elf.
123 * Thus we need to establish v8 scope within every C++ scope that constructs an object.
124 */
94 AdblockPlus::JsEnginePtr AdblockPlus::JsEngine::New(const AppInfo& appInfo, cons t ScopedV8IsolatePtr& isolate) 125 AdblockPlus::JsEnginePtr AdblockPlus::JsEngine::New(const AppInfo& appInfo, cons t ScopedV8IsolatePtr& isolate)
95 { 126 {
96 JsEnginePtr result(new JsEngine(isolate)); 127 auto isolateP = isolate->Get();
128 /*
129 * TODO: Remove `locker`.
130 * Until #3595 is fixed, unit tests allocate isolates outside of this class.
131 * Once we're no longer doing that, we may assume that this class holds
132 * exclusive access to the nascent isolate.
133 * The factory and constructor constitute a single-threaded usage,
134 * and there will be no need to lock the isolate.
135 */
136 const v8::Locker locker(isolateP);
137 /*
138 * Set up v8 scopes for isolate and handle.
139 * We cannot set up the v8 scope for context because it doesn't exist
140 * until after the constructor for `JsEngineInternal` returns.
141 */
142 const v8::Isolate::Scope isolateScope(isolateP);
143 const v8::HandleScope handleScope(isolateP);
97 144
98 const v8::Locker locker(result->GetIsolate()); 145 std::shared_ptr<JsEngineInternal> engine(std::make_shared<JsEngineInternal>(is olate));
99 const v8::Isolate::Scope isolateScope(result->GetIsolate());
100 const v8::HandleScope handleScope(result->GetIsolate());
101 146
102 result->context.reset(new v8::Persistent<v8::Context>(result->GetIsolate(), 147 JsEnginePtr result(engine);
103 v8::Context::New(result->GetIsolate()))); 148 // Establish a context scope for the legacy setup of the global object
149 const v8::Context::Scope contextScope(engine->GetContextAsLocal());
104 AdblockPlus::GlobalJsObject::Setup(result, appInfo, result->GetGlobalObject()) ; 150 AdblockPlus::GlobalJsObject::Setup(result, appInfo, result->GetGlobalObject()) ;
105 return result; 151 return result;
106 } 152 }
107 153
154 v8::Local<v8::Context> JsEngineInternal::GetContextAsLocal() const
155 {
156 return v8::Local<v8::Context>::New(isolate->Get(), context);
157 }
158
108 AdblockPlus::JsValuePtr AdblockPlus::JsEngine::GetGlobalObject() 159 AdblockPlus::JsValuePtr AdblockPlus::JsEngine::GetGlobalObject()
109 { 160 {
110 JsContext context(shared_from_this()); 161 return JsValuePtr(new JsValue(shared_from_this(), ToInternal(this)->GetGlobalO bject()));
111 return JsValuePtr(new JsValue(shared_from_this(), context.GetV8Context()->Glob al())); 162 }
163
164 v8::Local<v8::Object> JsEngineInternal::GetGlobalObject()
165 {
166 return GetContextAsLocal()->Global();
167 }
168
169 v8::Local<v8::Value> JsEngineInternal::ApplyFunction(
170 v8::Local<v8::Function> func,
171 AllocatedArray<v8::Local<v8::Value>> args)
172 {
173 return ApplyFunction(GetGlobalObject(), func, std::move(args));
174 }
175
176 v8::Local<v8::Value> JsEngineInternal::ApplyFunction(
177 v8::Local<v8::Object> thisObject,
178 v8::Local<v8::Function> func,
179 AllocatedArray<v8::Local<v8::Value>> args)
180 {
181 const v8::TryCatch tryCatch;
182 v8::Local<v8::Value> result = func->Call(thisObject, args.Size(), args.Get());
183 if (tryCatch.HasCaught())
184 {
185 throw AdblockPlus::JsError(tryCatch.Exception(), tryCatch.Message());
186 }
187 return result;
112 } 188 }
113 189
114 AdblockPlus::JsValuePtr AdblockPlus::JsEngine::Evaluate(const std::string& sourc e, 190 AdblockPlus::JsValuePtr AdblockPlus::JsEngine::Evaluate(const std::string& sourc e,
115 const std::string& filename) 191 const std::string& filename)
116 { 192 {
117 const JsContext context(shared_from_this()); 193 const JsContext context(shared_from_this());
118 const v8::TryCatch tryCatch; 194 const v8::TryCatch tryCatch;
119 const v8::Handle<v8::Script> script = CompileScript(GetIsolate(), source, 195 const v8::Handle<v8::Script> script = CompileScript(GetIsolate(), source,
120 filename); 196 filename);
121 CheckTryCatch(tryCatch); 197 CheckTryCatch(tryCatch);
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 const v8::Local<const v8::External> external = 268 const v8::Local<const v8::External> external =
193 v8::Local<const v8::External>::Cast(arguments.Data()); 269 v8::Local<const v8::External>::Cast(arguments.Data());
194 std::weak_ptr<JsEngine>* data = 270 std::weak_ptr<JsEngine>* data =
195 static_cast<std::weak_ptr<JsEngine>*>(external->Value()); 271 static_cast<std::weak_ptr<JsEngine>*>(external->Value());
196 JsEnginePtr result = data->lock(); 272 JsEnginePtr result = data->lock();
197 if (!result) 273 if (!result)
198 throw std::runtime_error("Oops, our JsEngine is gone, how did that happen?") ; 274 throw std::runtime_error("Oops, our JsEngine is gone, how did that happen?") ;
199 return result; 275 return result;
200 } 276 }
201 277
278 /**
279 * \par Implementation Notes
280 * We initialize the `Data()` element of the callback arguments with `this`,
281 * which raises an issue about life cycle.
282 * The result of `FunctionTemplate::New` is to create a function
283 * whose lifespan is the same as the context it's created in.
284 * The context is an instance member of the engine,
285 * so as long as the engine exists, so does the context.
286 * Since evaluation in v8 only occurs during the ordinary lifespan of the engine
287 * (i.e. after the constructor and before the destructor),
288 * the `this` pointer will be valid whenever the callback function might be ca lled.
289 */
290 v8::Local<v8::Function> JsEngineInternal::MakeCallback(v8::InvocationCallback ca llback)
291 {
292 return v8::FunctionTemplate::New(callback, v8::External::New(this))->GetFuncti on();
293 }
294
295 JsEngineInternal* JsEngineInternal::ExtractEngine(const v8::Arguments& arguments )
296 {
297 return static_cast<JsEngineInternal*>(v8::Local<v8::External>::Cast(arguments. Data())->Value());
298 }
299
202 AdblockPlus::JsValueList AdblockPlus::JsEngine::ConvertArguments(const v8::Argum ents& arguments) 300 AdblockPlus::JsValueList AdblockPlus::JsEngine::ConvertArguments(const v8::Argum ents& arguments)
203 { 301 {
204 const JsContext context(shared_from_this()); 302 const JsContext context(shared_from_this());
205 JsValueList list; 303 JsValueList list;
206 for (int i = 0; i < arguments.Length(); i++) 304 for (int i = 0; i < arguments.Length(); i++)
207 list.push_back(JsValuePtr(new JsValue(shared_from_this(), arguments[i]))); 305 list.push_back(JsValuePtr(new JsValue(shared_from_this(), arguments[i])));
208 return list; 306 return list;
209 } 307 }
210 308
211 AdblockPlus::FileSystemPtr AdblockPlus::JsEngine::GetFileSystem() 309 AdblockPlus::FileSystemPtr AdblockPlus::JsEngine::GetFileSystem()
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 } 344 }
247 345
248 void AdblockPlus::JsEngine::SetLogSystem(AdblockPlus::LogSystemPtr val) 346 void AdblockPlus::JsEngine::SetLogSystem(AdblockPlus::LogSystemPtr val)
249 { 347 {
250 if (!val) 348 if (!val)
251 throw std::runtime_error("LogSystem cannot be null"); 349 throw std::runtime_error("LogSystem cannot be null");
252 350
253 logSystem = val; 351 logSystem = val;
254 } 352 }
255 353
256
257 void AdblockPlus::JsEngine::SetGlobalProperty(const std::string& name, 354 void AdblockPlus::JsEngine::SetGlobalProperty(const std::string& name,
258 AdblockPlus::JsValuePtr value) 355 AdblockPlus::JsValuePtr value)
259 { 356 {
357 JsContext jsContext(shared_from_this());
260 auto global = GetGlobalObject(); 358 auto global = GetGlobalObject();
261 if (!global) 359 if (!global)
262 throw std::runtime_error("Global object cannot be null"); 360 throw std::runtime_error("Global object cannot be null");
263 global->SetProperty(name, value); 361 global->SetProperty(name, value);
264 } 362 }
265 363
266 void AdblockPlus::JsEngine::Schedule(std::function<void()> task, 364 void AdblockPlus::JsEngine::Schedule(std::function<void()> task,
267 AdblockPlus::ImmediateSingleUseThreadType) 365 AdblockPlus::ImmediateSingleUseThreadType)
268 { 366 {
269 // The present version of the scheduler only does immediate and single-use 367 // The present version of the scheduler only does immediate and single-use
270 // It does not, however, detach threads like the legacy thread behavior did. 368 // It does not, however, detach threads like the legacy thread behavior did.
271 scheduler->Run(task); 369 scheduler->Run(task);
272 } 370 }
273 371
274 void AdblockPlus::JsEngine::WaitForQuietScheduler() 372 void AdblockPlus::JsEngine::WaitForQuietScheduler()
275 { 373 {
276 scheduler->JoinAll(); 374 scheduler->JoinAll();
277 } 375 }
376
377 JsEngineInternal* ToInternal(AdblockPlus::JsEnginePtr p)
378 {
379 return static_cast<JsEngineInternal*>(p.get());
380 }
381
382 JsEngineInternal* ToInternal(AdblockPlus::JsEngine* p)
383 {
384 return static_cast<JsEngineInternal*>(p);
385 }
OLDNEW
« src/GlobalJsObject.cpp ('K') | « src/JsContext.cpp ('k') | src/JsEngineInternal.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld