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