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