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 22 namespace v8 { 23 24 25 // A single counter in a counter collection. 26 class Counter { 27 public: 28 static const int kMaxNameSize = 64; 29 int32_t* Bind(const char* name, bool histogram); ptr()30 int32_t* ptr() { return &count_; } count()31 int32_t count() { return count_; } sample_total()32 int32_t sample_total() { return sample_total_; } is_histogram()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 46 class 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 60 class CounterMap { 61 public: CounterMap()62 CounterMap(): hash_map_(Match) { } Lookup(const char * name)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 } Set(const char * name,Counter * value)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: Iterator(CounterMap * map)77 explicit Iterator(CounterMap* map) 78 : map_(&map->hash_map_), entry_(map_->Start()) { } Next()79 void Next() { entry_ = map_->Next(entry_); } More()80 bool More() { return entry_ != NULL; } CurrentKey()81 const char* CurrentKey() { return static_cast<const char*>(entry_->key); } CurrentValue()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 95 class SourceGroup { 96 public: SourceGroup()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 Begin(char ** argv,int offset)107 void Begin(char** argv, int offset) { 108 argv_ = const_cast<const char**>(argv); 109 begin_offset_ = offset; 110 } 111 End(int offset)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: IsolateThread(SourceGroup * group)123 explicit IsolateThread(SourceGroup* group) 124 : base::Thread(GetThreadOptions()), group_(group) {} 125 Run()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. 151 class ExternalizedContents { 152 public: ExternalizedContents(const ArrayBuffer::Contents & contents)153 explicit ExternalizedContents(const ArrayBuffer::Contents& contents) 154 : data_(contents.Data()), size_(contents.ByteLength()) {} ExternalizedContents(const SharedArrayBuffer::Contents & contents)155 explicit ExternalizedContents(const SharedArrayBuffer::Contents& contents) 156 : data_(contents.Data()), size_(contents.ByteLength()) {} ExternalizedContents(ExternalizedContents && other)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 180 class SerializationData { 181 public: SerializationData()182 SerializationData() : size_(0) {} 183 data()184 uint8_t* data() { return data_.get(); } size()185 size_t size() { return size_; } array_buffer_contents()186 const std::vector<ArrayBuffer::Contents>& array_buffer_contents() { 187 return array_buffer_contents_; 188 } 189 const std::vector<SharedArrayBuffer::Contents>& shared_array_buffer_contents()190 shared_array_buffer_contents() { 191 return shared_array_buffer_contents_; 192 } 193 AppendExternalizedContentsTo(std::vector<ExternalizedContents> * to)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 { operatorDataDeleter203 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 219 class 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 232 class 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: WorkerThread(Worker * worker)261 explicit WorkerThread(Worker* worker) 262 : base::Thread(base::Thread::Options("WorkerThread")), 263 worker_(worker) {} 264 Run()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 284 class ShellOptions { 285 public: ShellOptions()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 ~ShellOptions()310 ~ShellOptions() { 311 delete[] isolate_sources; 312 } 313 use_interactive_shell()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 342 class 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); ReadLine(const v8::FunctionCallbackInfo<v8::Value> & args)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