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