Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #ifndef V8_D8_H_
6 : #define V8_D8_H_
7 :
8 : #include <iterator>
9 : #include <map>
10 : #include <memory>
11 : #include <queue>
12 : #include <string>
13 : #include <unordered_map>
14 : #include <vector>
15 :
16 : #include "src/allocation.h"
17 : #include "src/async-hooks-wrapper.h"
18 : #include "src/base/platform/time.h"
19 : #include "src/string-hasher.h"
20 : #include "src/utils.h"
21 :
22 : #include "src/base/once.h"
23 :
24 :
25 : namespace v8 {
26 :
27 :
28 : // A single counter in a counter collection.
29 : class Counter {
30 : public:
31 : static const int kMaxNameSize = 64;
32 : int32_t* Bind(const char* name, bool histogram);
33 0 : int32_t* ptr() { return &count_; }
34 : int32_t count() { return count_; }
35 : int32_t sample_total() { return sample_total_; }
36 : bool is_histogram() { return is_histogram_; }
37 : void AddSample(int32_t sample);
38 : private:
39 : int32_t count_;
40 : int32_t sample_total_;
41 : bool is_histogram_;
42 : uint8_t name_[kMaxNameSize];
43 : };
44 :
45 :
46 : // A set of counters and associated information. An instance of this
47 : // class is stored directly in the memory-mapped counters file if
48 : // the --map-counters options is used
49 : class CounterCollection {
50 : public:
51 : CounterCollection();
52 : Counter* GetNextCounter();
53 : private:
54 : static const unsigned kMaxCounters = 512;
55 : uint32_t magic_number_;
56 : uint32_t max_counters_;
57 : uint32_t max_name_size_;
58 : uint32_t counters_in_use_;
59 : Counter counters_[kMaxCounters];
60 : };
61 :
62 : typedef std::unordered_map<std::string, Counter*> CounterMap;
63 :
64 : class SourceGroup {
65 : public:
66 30102 : SourceGroup()
67 : : next_semaphore_(0),
68 : done_semaphore_(0),
69 : thread_(nullptr),
70 : argv_(nullptr),
71 : begin_offset_(0),
72 30102 : end_offset_(0) {}
73 :
74 : ~SourceGroup();
75 :
76 : void Begin(char** argv, int offset) {
77 30102 : argv_ = const_cast<const char**>(argv);
78 30102 : begin_offset_ = offset;
79 : }
80 :
81 30102 : void End(int offset) { end_offset_ = offset; }
82 :
83 : // Returns true on success, false if an uncaught exception was thrown.
84 : bool Execute(Isolate* isolate);
85 :
86 : void StartExecuteInThread();
87 : void WaitForThread();
88 : void JoinThread();
89 :
90 : private:
91 0 : class IsolateThread : public base::Thread {
92 : public:
93 : explicit IsolateThread(SourceGroup* group);
94 :
95 0 : void Run() override { group_->ExecuteInThread(); }
96 :
97 : private:
98 : SourceGroup* group_;
99 : };
100 :
101 : void ExecuteInThread();
102 :
103 : base::Semaphore next_semaphore_;
104 : base::Semaphore done_semaphore_;
105 : base::Thread* thread_;
106 :
107 : void ExitShell(int exit_code);
108 : Local<String> ReadFile(Isolate* isolate, const char* name);
109 :
110 : const char** argv_;
111 : int begin_offset_;
112 : int end_offset_;
113 : };
114 :
115 : // The backing store of an ArrayBuffer or SharedArrayBuffer, after
116 : // Externalize() has been called on it.
117 : class ExternalizedContents {
118 : public:
119 : explicit ExternalizedContents(const ArrayBuffer::Contents& contents)
120 : : data_(contents.Data()),
121 : length_(contents.ByteLength()),
122 : deleter_(contents.Deleter()),
123 27 : deleter_data_(contents.DeleterData()) {}
124 : explicit ExternalizedContents(const SharedArrayBuffer::Contents& contents)
125 : : data_(contents.Data()),
126 : length_(contents.ByteLength()),
127 : deleter_(contents.Deleter()),
128 179 : deleter_data_(contents.DeleterData()) {}
129 : ExternalizedContents(ExternalizedContents&& other) V8_NOEXCEPT
130 308 : : data_(other.data_),
131 308 : length_(other.length_),
132 308 : deleter_(other.deleter_),
133 924 : deleter_data_(other.deleter_data_) {
134 308 : other.data_ = nullptr;
135 308 : other.length_ = 0;
136 308 : other.deleter_ = nullptr;
137 308 : other.deleter_data_ = nullptr;
138 : }
139 : ExternalizedContents& operator=(ExternalizedContents&& other) V8_NOEXCEPT {
140 0 : if (this != &other) {
141 0 : data_ = other.data_;
142 0 : length_ = other.length_;
143 0 : deleter_ = other.deleter_;
144 0 : deleter_data_ = other.deleter_data_;
145 0 : other.data_ = nullptr;
146 0 : other.length_ = 0;
147 0 : other.deleter_ = nullptr;
148 0 : other.deleter_data_ = nullptr;
149 : }
150 : return *this;
151 : }
152 : ~ExternalizedContents();
153 :
154 : private:
155 : void* data_;
156 : size_t length_;
157 : ArrayBuffer::Contents::DeleterCallback deleter_;
158 : void* deleter_data_;
159 :
160 : DISALLOW_COPY_AND_ASSIGN(ExternalizedContents);
161 : };
162 :
163 3776 : class SerializationData {
164 : public:
165 1885 : SerializationData() : size_(0) {}
166 :
167 : uint8_t* data() { return data_.get(); }
168 : size_t size() { return size_; }
169 : const std::vector<ArrayBuffer::Contents>& array_buffer_contents() {
170 : return array_buffer_contents_;
171 : }
172 : const std::vector<SharedArrayBuffer::Contents>&
173 : shared_array_buffer_contents() {
174 : return shared_array_buffer_contents_;
175 : }
176 : const std::vector<WasmModuleObject::TransferrableModule>&
177 : transferrable_modules() {
178 : return transferrable_modules_;
179 : }
180 :
181 : private:
182 : struct DataDeleter {
183 1699 : void operator()(uint8_t* p) const { free(p); }
184 : };
185 :
186 : std::unique_ptr<uint8_t, DataDeleter> data_;
187 : size_t size_;
188 : std::vector<ArrayBuffer::Contents> array_buffer_contents_;
189 : std::vector<SharedArrayBuffer::Contents> shared_array_buffer_contents_;
190 : std::vector<WasmModuleObject::TransferrableModule> transferrable_modules_;
191 :
192 : private:
193 : friend class Serializer;
194 :
195 : DISALLOW_COPY_AND_ASSIGN(SerializationData);
196 : };
197 :
198 :
199 1923 : class SerializationDataQueue {
200 : public:
201 : void Enqueue(std::unique_ptr<SerializationData> data);
202 : bool Dequeue(std::unique_ptr<SerializationData>* data);
203 : bool IsEmpty();
204 : void Clear();
205 :
206 : private:
207 : base::Mutex mutex_;
208 : std::vector<std::unique_ptr<SerializationData>> data_;
209 : };
210 :
211 :
212 : class Worker {
213 : public:
214 : Worker();
215 : ~Worker();
216 :
217 : // Run the given script on this Worker. This function should only be called
218 : // once, and should only be called by the thread that created the Worker.
219 : void StartExecuteInThread(const char* script);
220 : // Post a message to the worker's incoming message queue. The worker will
221 : // take ownership of the SerializationData.
222 : // This function should only be called by the thread that created the Worker.
223 : void PostMessage(std::unique_ptr<SerializationData> data);
224 : // Synchronously retrieve messages from the worker's outgoing message queue.
225 : // If there is no message in the queue, block until a message is available.
226 : // If there are no messages in the queue and the worker is no longer running,
227 : // return nullptr.
228 : // This function should only be called by the thread that created the Worker.
229 : std::unique_ptr<SerializationData> GetMessage();
230 : // Terminate the worker's event loop. Messages from the worker that have been
231 : // queued can still be read via GetMessage().
232 : // This function can be called by any thread.
233 : void Terminate();
234 : // Terminate and join the thread.
235 : // This function can be called by any thread.
236 : void WaitForThread();
237 :
238 : private:
239 641 : class WorkerThread : public base::Thread {
240 : public:
241 : explicit WorkerThread(Worker* worker)
242 : : base::Thread(base::Thread::Options("WorkerThread")),
243 641 : worker_(worker) {}
244 :
245 641 : void Run() override { worker_->ExecuteInThread(); }
246 :
247 : private:
248 : Worker* worker_;
249 : };
250 :
251 : void ExecuteInThread();
252 : static void PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args);
253 :
254 : base::Semaphore in_semaphore_;
255 : base::Semaphore out_semaphore_;
256 : SerializationDataQueue in_queue_;
257 : SerializationDataQueue out_queue_;
258 : base::Thread* thread_;
259 : char* script_;
260 : base::Atomic32 running_;
261 : };
262 :
263 : class PerIsolateData {
264 : public:
265 : explicit PerIsolateData(Isolate* isolate);
266 :
267 : ~PerIsolateData();
268 :
269 : inline static PerIsolateData* Get(Isolate* isolate) {
270 : return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
271 : }
272 :
273 : class RealmScope {
274 : public:
275 : explicit RealmScope(PerIsolateData* data);
276 : ~RealmScope();
277 :
278 : private:
279 : PerIsolateData* data_;
280 : };
281 :
282 : inline void SetTimeout(Local<Function> callback, Local<Context> context);
283 : inline MaybeLocal<Function> GetTimeoutCallback();
284 : inline MaybeLocal<Context> GetTimeoutContext();
285 :
286 : AsyncHooks* GetAsyncHooks() { return async_hooks_wrapper_; }
287 :
288 : private:
289 : friend class Shell;
290 : friend class RealmScope;
291 : Isolate* isolate_;
292 : int realm_count_;
293 : int realm_current_;
294 : int realm_switch_;
295 : Global<Context>* realms_;
296 : Global<Value> realm_shared_;
297 : std::queue<Global<Function>> set_timeout_callbacks_;
298 : std::queue<Global<Context>> set_timeout_contexts_;
299 : AsyncHooks* async_hooks_wrapper_;
300 :
301 : int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
302 : int arg_offset);
303 : int RealmFind(Local<Context> context);
304 : };
305 :
306 : class ShellOptions {
307 : public:
308 : enum CodeCacheOptions {
309 : kNoProduceCache,
310 : kProduceCache,
311 : kProduceCacheAfterExecute
312 : };
313 :
314 30102 : ShellOptions()
315 : : send_idle_notification(false),
316 : invoke_weak_callbacks(false),
317 : omit_quit(false),
318 : wait_for_wasm(true),
319 : stress_opt(false),
320 : stress_deopt(false),
321 : stress_runs(1),
322 : interactive_shell(false),
323 : test_shell(false),
324 : expected_to_throw(false),
325 : mock_arraybuffer_allocator(false),
326 : enable_inspector(false),
327 : num_isolates(1),
328 : compile_options(v8::ScriptCompiler::kNoCompileOptions),
329 : stress_background_compile(false),
330 : code_cache_options(CodeCacheOptions::kNoProduceCache),
331 : isolate_sources(nullptr),
332 : icu_data_file(nullptr),
333 : natives_blob(nullptr),
334 : snapshot_blob(nullptr),
335 : trace_enabled(false),
336 : trace_path(nullptr),
337 : trace_config(nullptr),
338 : lcov_file(nullptr),
339 : disable_in_process_stack_traces(false),
340 60204 : read_from_tcp_port(-1) {}
341 :
342 60204 : ~ShellOptions() {
343 30102 : delete[] isolate_sources;
344 30102 : }
345 :
346 : bool send_idle_notification;
347 : bool invoke_weak_callbacks;
348 : bool omit_quit;
349 : bool wait_for_wasm;
350 : bool stress_opt;
351 : bool stress_deopt;
352 : int stress_runs;
353 : bool interactive_shell;
354 : bool test_shell;
355 : bool expected_to_throw;
356 : bool mock_arraybuffer_allocator;
357 : size_t mock_arraybuffer_allocator_limit = 0;
358 : bool enable_inspector;
359 : int num_isolates;
360 : v8::ScriptCompiler::CompileOptions compile_options;
361 : bool stress_background_compile;
362 : CodeCacheOptions code_cache_options;
363 : SourceGroup* isolate_sources;
364 : const char* icu_data_file;
365 : const char* natives_blob;
366 : const char* snapshot_blob;
367 : bool trace_enabled;
368 : const char* trace_path;
369 : const char* trace_config;
370 : const char* lcov_file;
371 : bool disable_in_process_stack_traces;
372 : int read_from_tcp_port;
373 : bool enable_os_system = false;
374 : bool quiet_load = false;
375 : int thread_pool_size = 0;
376 : bool stress_delay_tasks = false;
377 : std::vector<const char*> arguments;
378 : bool include_arguments = true;
379 : };
380 :
381 : class Shell : public i::AllStatic {
382 : public:
383 : enum PrintResult : bool { kPrintResult = true, kNoPrintResult = false };
384 : enum ReportExceptions : bool {
385 : kReportExceptions = true,
386 : kNoReportExceptions = false
387 : };
388 : enum ProcessMessageQueue : bool {
389 : kProcessMessageQueue = true,
390 : kNoProcessMessageQueue = false
391 : };
392 :
393 : static bool ExecuteString(Isolate* isolate, Local<String> source,
394 : Local<Value> name, PrintResult print_result,
395 : ReportExceptions report_exceptions,
396 : ProcessMessageQueue process_message_queue);
397 : static bool ExecuteModule(Isolate* isolate, const char* file_name);
398 : static void ReportException(Isolate* isolate, TryCatch* try_catch);
399 : static Local<String> ReadFile(Isolate* isolate, const char* name);
400 : static Local<Context> CreateEvaluationContext(Isolate* isolate);
401 : static int RunMain(Isolate* isolate, int argc, char* argv[], bool last_run);
402 : static int Main(int argc, char* argv[]);
403 : static void Exit(int exit_code);
404 : static void OnExit(Isolate* isolate);
405 : static void CollectGarbage(Isolate* isolate);
406 : static bool EmptyMessageQueues(Isolate* isolate);
407 : static bool CompleteMessageLoop(Isolate* isolate);
408 :
409 : static std::unique_ptr<SerializationData> SerializeValue(
410 : Isolate* isolate, Local<Value> value, Local<Value> transfer);
411 : static MaybeLocal<Value> DeserializeValue(
412 : Isolate* isolate, std::unique_ptr<SerializationData> data);
413 : static void CleanupWorkers();
414 : static int* LookupCounter(const char* name);
415 : static void* CreateHistogram(const char* name,
416 : int min,
417 : int max,
418 : size_t buckets);
419 : static void AddHistogramSample(void* histogram, int sample);
420 : static void MapCounters(v8::Isolate* isolate, const char* name);
421 :
422 : static void PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args);
423 :
424 : static void RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args);
425 : static void RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args);
426 : static void RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args);
427 : static void RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args);
428 : static void RealmNavigate(const v8::FunctionCallbackInfo<v8::Value>& args);
429 : static void RealmCreateAllowCrossRealmAccess(
430 : const v8::FunctionCallbackInfo<v8::Value>& args);
431 : static void RealmDetachGlobal(
432 : const v8::FunctionCallbackInfo<v8::Value>& args);
433 : static void RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args);
434 : static void RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args);
435 : static void RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args);
436 : static void RealmSharedGet(Local<String> property,
437 : const PropertyCallbackInfo<Value>& info);
438 : static void RealmSharedSet(Local<String> property,
439 : Local<Value> value,
440 : const PropertyCallbackInfo<void>& info);
441 :
442 : static void AsyncHooksCreateHook(
443 : const v8::FunctionCallbackInfo<v8::Value>& args);
444 : static void AsyncHooksExecutionAsyncId(
445 : const v8::FunctionCallbackInfo<v8::Value>& args);
446 : static void AsyncHooksTriggerAsyncId(
447 : const v8::FunctionCallbackInfo<v8::Value>& args);
448 :
449 : static void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
450 : static void PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args);
451 : static void Write(const v8::FunctionCallbackInfo<v8::Value>& args);
452 : static void WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args);
453 : static void NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args);
454 : static void QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args);
455 : static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
456 : static void Version(const v8::FunctionCallbackInfo<v8::Value>& args);
457 : static void Read(const v8::FunctionCallbackInfo<v8::Value>& args);
458 : static void ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args);
459 : static Local<String> ReadFromStdin(Isolate* isolate);
460 0 : static void ReadLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
461 0 : args.GetReturnValue().Set(ReadFromStdin(args.GetIsolate()));
462 0 : }
463 : static void Load(const v8::FunctionCallbackInfo<v8::Value>& args);
464 : static void SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args);
465 : static void WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args);
466 : static void WorkerPostMessage(
467 : const v8::FunctionCallbackInfo<v8::Value>& args);
468 : static void WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
469 : static void WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args);
470 : // The OS object on the global object contains methods for performing
471 : // operating system calls:
472 : //
473 : // os.system("program_name", ["arg1", "arg2", ...], timeout1, timeout2) will
474 : // run the command, passing the arguments to the program. The standard output
475 : // of the program will be picked up and returned as a multiline string. If
476 : // timeout1 is present then it should be a number. -1 indicates no timeout
477 : // and a positive number is used as a timeout in milliseconds that limits the
478 : // time spent waiting between receiving output characters from the program.
479 : // timeout2, if present, should be a number indicating the limit in
480 : // milliseconds on the total running time of the program. Exceptions are
481 : // thrown on timeouts or other errors or if the exit status of the program
482 : // indicates an error.
483 : //
484 : // os.chdir(dir) changes directory to the given directory. Throws an
485 : // exception/ on error.
486 : //
487 : // os.setenv(variable, value) sets an environment variable. Repeated calls to
488 : // this method leak memory due to the API of setenv in the standard C library.
489 : //
490 : // os.umask(alue) calls the umask system call and returns the old umask.
491 : //
492 : // os.mkdirp(name, mask) creates a directory. The mask (if present) is anded
493 : // with the current umask. Intermediate directories are created if necessary.
494 : // An exception is not thrown if the directory already exists. Analogous to
495 : // the "mkdir -p" command.
496 : static void System(const v8::FunctionCallbackInfo<v8::Value>& args);
497 : static void ChangeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
498 : static void SetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
499 : static void UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
500 : static void SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args);
501 : static void MakeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
502 : static void RemoveDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
503 : static MaybeLocal<Promise> HostImportModuleDynamically(
504 : Local<Context> context, Local<ScriptOrModule> referrer,
505 : Local<String> specifier);
506 : static void HostInitializeImportMetaObject(Local<Context> context,
507 : Local<Module> module,
508 : Local<Object> meta);
509 :
510 : // Data is of type DynamicImportData*. We use void* here to be able
511 : // to conform with MicrotaskCallback interface and enqueue this
512 : // function in the microtask queue.
513 : static void DoHostImportModuleDynamically(void* data);
514 : static void AddOSMethods(v8::Isolate* isolate,
515 : Local<ObjectTemplate> os_template);
516 :
517 : static const char* kPrompt;
518 : static ShellOptions options;
519 : static ArrayBuffer::Allocator* array_buffer_allocator;
520 :
521 : static void SetWaitUntilDone(Isolate* isolate, bool value);
522 :
523 : static char* ReadCharsFromTcpPort(const char* name, int* size_out);
524 :
525 : static void set_script_executed() { script_executed_.store(true); }
526 59966 : static bool use_interactive_shell() {
527 119932 : return (options.interactive_shell || !script_executed_.load()) &&
528 59966 : !options.test_shell;
529 : }
530 :
531 : private:
532 : static Global<Context> evaluation_context_;
533 : static base::OnceType quit_once_;
534 : static Global<Function> stringify_function_;
535 : static const char* stringify_source_;
536 : static CounterMap* counter_map_;
537 : // We statically allocate a set of local counters to be used if we
538 : // don't want to store the stats in a memory-mapped file
539 : static CounterCollection local_counters_;
540 : static CounterCollection* counters_;
541 : static base::OS::MemoryMappedFile* counters_file_;
542 : static base::LazyMutex context_mutex_;
543 : static const base::TimeTicks kInitialTicks;
544 :
545 : static base::LazyMutex workers_mutex_; // Guards the following members.
546 : static bool allow_new_workers_;
547 : static std::vector<Worker*> workers_;
548 : static std::vector<ExternalizedContents> externalized_contents_;
549 :
550 : // Multiple isolates may update this flag concurrently.
551 : static std::atomic<bool> script_executed_;
552 :
553 : static void WriteIgnitionDispatchCountersFile(v8::Isolate* isolate);
554 : // Append LCOV coverage data to file.
555 : static void WriteLcovData(v8::Isolate* isolate, const char* file);
556 : static Counter* GetCounter(const char* name, bool is_histogram);
557 : static Local<String> Stringify(Isolate* isolate, Local<Value> value);
558 : static void Initialize(Isolate* isolate);
559 : static void RunShell(Isolate* isolate);
560 : static bool SetOptions(int argc, char* argv[]);
561 : static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate);
562 : static MaybeLocal<Context> CreateRealm(
563 : const v8::FunctionCallbackInfo<v8::Value>& args, int index,
564 : v8::MaybeLocal<Value> global_object);
565 : static void DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
566 : int index);
567 : static MaybeLocal<Module> FetchModuleTree(v8::Local<v8::Context> context,
568 : const std::string& file_name);
569 : static ScriptCompiler::CachedData* LookupCodeCache(Isolate* isolate,
570 : Local<Value> name);
571 : static void StoreInCodeCache(Isolate* isolate, Local<Value> name,
572 : const ScriptCompiler::CachedData* data);
573 : // We may have multiple isolates running concurrently, so the access to
574 : // the isolate_status_ needs to be concurrency-safe.
575 : static base::LazyMutex isolate_status_lock_;
576 : static std::map<Isolate*, bool> isolate_status_;
577 :
578 : static base::LazyMutex cached_code_mutex_;
579 : static std::map<std::string, std::unique_ptr<ScriptCompiler::CachedData>>
580 : cached_code_map_;
581 : };
582 :
583 :
584 : } // namespace v8
585 :
586 :
587 : #endif // V8_D8_H_
|