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