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