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 <memory>
10#include <string>
11#include <vector>
12
13#include "src/allocation.h"
14#include "src/base/hashmap.h"
15#include "src/base/platform/time.h"
16#include "src/list.h"
17#include "src/utils.h"
18
19#include "src/base/once.h"
20
21
22namespace v8 {
23
24
25// A single counter in a counter collection.
26class Counter {
27 public:
28  static const int kMaxNameSize = 64;
29  int32_t* Bind(const char* name, bool histogram);
30  int32_t* ptr() { return &count_; }
31  int32_t count() { return count_; }
32  int32_t sample_total() { return sample_total_; }
33  bool is_histogram() { return is_histogram_; }
34  void AddSample(int32_t sample);
35 private:
36  int32_t count_;
37  int32_t sample_total_;
38  bool is_histogram_;
39  uint8_t name_[kMaxNameSize];
40};
41
42
43// A set of counters and associated information.  An instance of this
44// class is stored directly in the memory-mapped counters file if
45// the --map-counters options is used
46class CounterCollection {
47 public:
48  CounterCollection();
49  Counter* GetNextCounter();
50 private:
51  static const unsigned kMaxCounters = 512;
52  uint32_t magic_number_;
53  uint32_t max_counters_;
54  uint32_t max_name_size_;
55  uint32_t counters_in_use_;
56  Counter counters_[kMaxCounters];
57};
58
59
60class CounterMap {
61 public:
62  CounterMap(): hash_map_(Match) { }
63  Counter* Lookup(const char* name) {
64    base::HashMap::Entry* answer =
65        hash_map_.Lookup(const_cast<char*>(name), Hash(name));
66    if (!answer) return NULL;
67    return reinterpret_cast<Counter*>(answer->value);
68  }
69  void Set(const char* name, Counter* value) {
70    base::HashMap::Entry* answer =
71        hash_map_.LookupOrInsert(const_cast<char*>(name), Hash(name));
72    DCHECK(answer != NULL);
73    answer->value = value;
74  }
75  class Iterator {
76   public:
77    explicit Iterator(CounterMap* map)
78        : map_(&map->hash_map_), entry_(map_->Start()) { }
79    void Next() { entry_ = map_->Next(entry_); }
80    bool More() { return entry_ != NULL; }
81    const char* CurrentKey() { return static_cast<const char*>(entry_->key); }
82    Counter* CurrentValue() { return static_cast<Counter*>(entry_->value); }
83   private:
84    base::CustomMatcherHashMap* map_;
85    base::CustomMatcherHashMap::Entry* entry_;
86  };
87
88 private:
89  static int Hash(const char* name);
90  static bool Match(void* key1, void* key2);
91  base::CustomMatcherHashMap hash_map_;
92};
93
94
95class SourceGroup {
96 public:
97  SourceGroup() :
98      next_semaphore_(0),
99      done_semaphore_(0),
100      thread_(NULL),
101      argv_(NULL),
102      begin_offset_(0),
103      end_offset_(0) {}
104
105  ~SourceGroup();
106
107  void Begin(char** argv, int offset) {
108    argv_ = const_cast<const char**>(argv);
109    begin_offset_ = offset;
110  }
111
112  void End(int offset) { end_offset_ = offset; }
113
114  void Execute(Isolate* isolate);
115
116  void StartExecuteInThread();
117  void WaitForThread();
118  void JoinThread();
119
120 private:
121  class IsolateThread : public base::Thread {
122   public:
123    explicit IsolateThread(SourceGroup* group)
124        : base::Thread(GetThreadOptions()), group_(group) {}
125
126    virtual void Run() {
127      group_->ExecuteInThread();
128    }
129
130   private:
131    SourceGroup* group_;
132  };
133
134  static base::Thread::Options GetThreadOptions();
135  void ExecuteInThread();
136
137  base::Semaphore next_semaphore_;
138  base::Semaphore done_semaphore_;
139  base::Thread* thread_;
140
141  void ExitShell(int exit_code);
142  Local<String> ReadFile(Isolate* isolate, const char* name);
143
144  const char** argv_;
145  int begin_offset_;
146  int end_offset_;
147};
148
149// The backing store of an ArrayBuffer or SharedArrayBuffer, after
150// Externalize() has been called on it.
151class ExternalizedContents {
152 public:
153  explicit ExternalizedContents(const ArrayBuffer::Contents& contents)
154      : data_(contents.Data()), size_(contents.ByteLength()) {}
155  explicit ExternalizedContents(const SharedArrayBuffer::Contents& contents)
156      : data_(contents.Data()), size_(contents.ByteLength()) {}
157  ExternalizedContents(ExternalizedContents&& other)
158      : data_(other.data_), size_(other.size_) {
159    other.data_ = nullptr;
160    other.size_ = 0;
161  }
162  ExternalizedContents& operator=(ExternalizedContents&& other) {
163    if (this != &other) {
164      data_ = other.data_;
165      size_ = other.size_;
166      other.data_ = nullptr;
167      other.size_ = 0;
168    }
169    return *this;
170  }
171  ~ExternalizedContents();
172
173 private:
174  void* data_;
175  size_t size_;
176
177  DISALLOW_COPY_AND_ASSIGN(ExternalizedContents);
178};
179
180class SerializationData {
181 public:
182  SerializationData() : size_(0) {}
183
184  uint8_t* data() { return data_.get(); }
185  size_t size() { return size_; }
186  const std::vector<ArrayBuffer::Contents>& array_buffer_contents() {
187    return array_buffer_contents_;
188  }
189  const std::vector<SharedArrayBuffer::Contents>&
190  shared_array_buffer_contents() {
191    return shared_array_buffer_contents_;
192  }
193
194  void AppendExternalizedContentsTo(std::vector<ExternalizedContents>* to) {
195    to->insert(to->end(),
196               std::make_move_iterator(externalized_contents_.begin()),
197               std::make_move_iterator(externalized_contents_.end()));
198    externalized_contents_.clear();
199  }
200
201 private:
202  struct DataDeleter {
203    void operator()(uint8_t* p) const { free(p); }
204  };
205
206  std::unique_ptr<uint8_t, DataDeleter> data_;
207  size_t size_;
208  std::vector<ArrayBuffer::Contents> array_buffer_contents_;
209  std::vector<SharedArrayBuffer::Contents> shared_array_buffer_contents_;
210  std::vector<ExternalizedContents> externalized_contents_;
211
212 private:
213  friend class Serializer;
214
215  DISALLOW_COPY_AND_ASSIGN(SerializationData);
216};
217
218
219class SerializationDataQueue {
220 public:
221  void Enqueue(std::unique_ptr<SerializationData> data);
222  bool Dequeue(std::unique_ptr<SerializationData>* data);
223  bool IsEmpty();
224  void Clear();
225
226 private:
227  base::Mutex mutex_;
228  std::vector<std::unique_ptr<SerializationData>> data_;
229};
230
231
232class Worker {
233 public:
234  Worker();
235  ~Worker();
236
237  // Run the given script on this Worker. This function should only be called
238  // once, and should only be called by the thread that created the Worker.
239  void StartExecuteInThread(const char* script);
240  // Post a message to the worker's incoming message queue. The worker will
241  // take ownership of the SerializationData.
242  // This function should only be called by the thread that created the Worker.
243  void PostMessage(std::unique_ptr<SerializationData> data);
244  // Synchronously retrieve messages from the worker's outgoing message queue.
245  // If there is no message in the queue, block until a message is available.
246  // If there are no messages in the queue and the worker is no longer running,
247  // return nullptr.
248  // This function should only be called by the thread that created the Worker.
249  std::unique_ptr<SerializationData> GetMessage();
250  // Terminate the worker's event loop. Messages from the worker that have been
251  // queued can still be read via GetMessage().
252  // This function can be called by any thread.
253  void Terminate();
254  // Terminate and join the thread.
255  // This function can be called by any thread.
256  void WaitForThread();
257
258 private:
259  class WorkerThread : public base::Thread {
260   public:
261    explicit WorkerThread(Worker* worker)
262        : base::Thread(base::Thread::Options("WorkerThread")),
263          worker_(worker) {}
264
265    virtual void Run() { worker_->ExecuteInThread(); }
266
267   private:
268    Worker* worker_;
269  };
270
271  void ExecuteInThread();
272  static void PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args);
273
274  base::Semaphore in_semaphore_;
275  base::Semaphore out_semaphore_;
276  SerializationDataQueue in_queue_;
277  SerializationDataQueue out_queue_;
278  base::Thread* thread_;
279  char* script_;
280  base::Atomic32 running_;
281};
282
283
284class ShellOptions {
285 public:
286  ShellOptions()
287      : script_executed(false),
288        send_idle_notification(false),
289        invoke_weak_callbacks(false),
290        omit_quit(false),
291        stress_opt(false),
292        stress_deopt(false),
293        stress_runs(1),
294        interactive_shell(false),
295        test_shell(false),
296        dump_heap_constants(false),
297        expected_to_throw(false),
298        mock_arraybuffer_allocator(false),
299        enable_inspector(false),
300        num_isolates(1),
301        compile_options(v8::ScriptCompiler::kNoCompileOptions),
302        isolate_sources(NULL),
303        icu_data_file(NULL),
304        natives_blob(NULL),
305        snapshot_blob(NULL),
306        trace_enabled(false),
307        trace_config(NULL),
308        lcov_file(NULL) {}
309
310  ~ShellOptions() {
311    delete[] isolate_sources;
312  }
313
314  bool use_interactive_shell() {
315    return (interactive_shell || !script_executed) && !test_shell;
316  }
317
318  bool script_executed;
319  bool send_idle_notification;
320  bool invoke_weak_callbacks;
321  bool omit_quit;
322  bool stress_opt;
323  bool stress_deopt;
324  int stress_runs;
325  bool interactive_shell;
326  bool test_shell;
327  bool dump_heap_constants;
328  bool expected_to_throw;
329  bool mock_arraybuffer_allocator;
330  bool enable_inspector;
331  int num_isolates;
332  v8::ScriptCompiler::CompileOptions compile_options;
333  SourceGroup* isolate_sources;
334  const char* icu_data_file;
335  const char* natives_blob;
336  const char* snapshot_blob;
337  bool trace_enabled;
338  const char* trace_config;
339  const char* lcov_file;
340};
341
342class Shell : public i::AllStatic {
343 public:
344  static MaybeLocal<Script> CompileString(
345      Isolate* isolate, Local<String> source, Local<Value> name,
346      v8::ScriptCompiler::CompileOptions compile_options);
347  static bool ExecuteString(Isolate* isolate, Local<String> source,
348                            Local<Value> name, bool print_result,
349                            bool report_exceptions);
350  static bool ExecuteModule(Isolate* isolate, const char* file_name);
351  static void ReportException(Isolate* isolate, TryCatch* try_catch);
352  static Local<String> ReadFile(Isolate* isolate, const char* name);
353  static Local<Context> CreateEvaluationContext(Isolate* isolate);
354  static int RunMain(Isolate* isolate, int argc, char* argv[], bool last_run);
355  static int Main(int argc, char* argv[]);
356  static void Exit(int exit_code);
357  static void OnExit(Isolate* isolate);
358  static void CollectGarbage(Isolate* isolate);
359  static void EmptyMessageQueues(Isolate* isolate);
360
361  static std::unique_ptr<SerializationData> SerializeValue(
362      Isolate* isolate, Local<Value> value, Local<Value> transfer);
363  static MaybeLocal<Value> DeserializeValue(
364      Isolate* isolate, std::unique_ptr<SerializationData> data);
365  static void CleanupWorkers();
366  static int* LookupCounter(const char* name);
367  static void* CreateHistogram(const char* name,
368                               int min,
369                               int max,
370                               size_t buckets);
371  static void AddHistogramSample(void* histogram, int sample);
372  static void MapCounters(v8::Isolate* isolate, const char* name);
373
374  static void PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args);
375
376  static void RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args);
377  static void RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args);
378  static void RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args);
379  static void RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args);
380  static void RealmNavigate(const v8::FunctionCallbackInfo<v8::Value>& args);
381  static void RealmCreateAllowCrossRealmAccess(
382      const v8::FunctionCallbackInfo<v8::Value>& args);
383  static void RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args);
384  static void RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args);
385  static void RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args);
386  static void RealmSharedGet(Local<String> property,
387                             const  PropertyCallbackInfo<Value>& info);
388  static void RealmSharedSet(Local<String> property,
389                             Local<Value> value,
390                             const  PropertyCallbackInfo<void>& info);
391
392  static void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
393  static void PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args);
394  static void Write(const v8::FunctionCallbackInfo<v8::Value>& args);
395  static void QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args);
396  static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
397  static void Version(const v8::FunctionCallbackInfo<v8::Value>& args);
398  static void Read(const v8::FunctionCallbackInfo<v8::Value>& args);
399  static void ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args);
400  static Local<String> ReadFromStdin(Isolate* isolate);
401  static void ReadLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
402    args.GetReturnValue().Set(ReadFromStdin(args.GetIsolate()));
403  }
404  static void Load(const v8::FunctionCallbackInfo<v8::Value>& args);
405  static void WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args);
406  static void WorkerPostMessage(
407      const v8::FunctionCallbackInfo<v8::Value>& args);
408  static void WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
409  static void WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args);
410  // The OS object on the global object contains methods for performing
411  // operating system calls:
412  //
413  // os.system("program_name", ["arg1", "arg2", ...], timeout1, timeout2) will
414  // run the command, passing the arguments to the program.  The standard output
415  // of the program will be picked up and returned as a multiline string.  If
416  // timeout1 is present then it should be a number.  -1 indicates no timeout
417  // and a positive number is used as a timeout in milliseconds that limits the
418  // time spent waiting between receiving output characters from the program.
419  // timeout2, if present, should be a number indicating the limit in
420  // milliseconds on the total running time of the program.  Exceptions are
421  // thrown on timeouts or other errors or if the exit status of the program
422  // indicates an error.
423  //
424  // os.chdir(dir) changes directory to the given directory.  Throws an
425  // exception/ on error.
426  //
427  // os.setenv(variable, value) sets an environment variable.  Repeated calls to
428  // this method leak memory due to the API of setenv in the standard C library.
429  //
430  // os.umask(alue) calls the umask system call and returns the old umask.
431  //
432  // os.mkdirp(name, mask) creates a directory.  The mask (if present) is anded
433  // with the current umask.  Intermediate directories are created if necessary.
434  // An exception is not thrown if the directory already exists.  Analogous to
435  // the "mkdir -p" command.
436  static void System(const v8::FunctionCallbackInfo<v8::Value>& args);
437  static void ChangeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
438  static void SetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
439  static void UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
440  static void SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args);
441  static void MakeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
442  static void RemoveDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
443
444  static void AddOSMethods(v8::Isolate* isolate,
445                           Local<ObjectTemplate> os_template);
446
447  static const char* kPrompt;
448  static ShellOptions options;
449  static ArrayBuffer::Allocator* array_buffer_allocator;
450
451 private:
452  static Global<Context> evaluation_context_;
453  static base::OnceType quit_once_;
454  static Global<Function> stringify_function_;
455  static CounterMap* counter_map_;
456  // We statically allocate a set of local counters to be used if we
457  // don't want to store the stats in a memory-mapped file
458  static CounterCollection local_counters_;
459  static CounterCollection* counters_;
460  static base::OS::MemoryMappedFile* counters_file_;
461  static base::LazyMutex context_mutex_;
462  static const base::TimeTicks kInitialTicks;
463
464  static base::LazyMutex workers_mutex_;
465  static bool allow_new_workers_;
466  static i::List<Worker*> workers_;
467  static std::vector<ExternalizedContents> externalized_contents_;
468
469  static void WriteIgnitionDispatchCountersFile(v8::Isolate* isolate);
470  // Append LCOV coverage data to file.
471  static void WriteLcovData(v8::Isolate* isolate, const char* file);
472  static Counter* GetCounter(const char* name, bool is_histogram);
473  static Local<String> Stringify(Isolate* isolate, Local<Value> value);
474  static void Initialize(Isolate* isolate);
475  static void RunShell(Isolate* isolate);
476  static bool SetOptions(int argc, char* argv[]);
477  static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate);
478  static MaybeLocal<Context> CreateRealm(
479      const v8::FunctionCallbackInfo<v8::Value>& args, int index,
480      v8::MaybeLocal<Value> global_object);
481  static void DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
482                           int index);
483  static MaybeLocal<Module> FetchModuleTree(v8::Local<v8::Context> context,
484                                            const std::string& file_name);
485};
486
487
488}  // namespace v8
489
490
491#endif  // V8_D8_H_
492