Home | History | Annotate | Download | only in src
      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 <map>
     10 #include <memory>
     11 #include <queue>
     12 #include <string>
     13 #include <unordered_map>
     14 #include <vector>
     15 
     16 #include "src/allocation.h"
     17 #include "src/async-hooks-wrapper.h"
     18 #include "src/base/platform/time.h"
     19 #include "src/string-hasher.h"
     20 #include "src/utils.h"
     21 
     22 #include "src/base/once.h"
     23 
     24 
     25 namespace v8 {
     26 
     27 
     28 // A single counter in a counter collection.
     29 class Counter {
     30  public:
     31   static const int kMaxNameSize = 64;
     32   int32_t* Bind(const char* name, bool histogram);
     33   int32_t* ptr() { return &count_; }
     34   int32_t count() { return count_; }
     35   int32_t sample_total() { return sample_total_; }
     36   bool is_histogram() { return is_histogram_; }
     37   void AddSample(int32_t sample);
     38  private:
     39   int32_t count_;
     40   int32_t sample_total_;
     41   bool is_histogram_;
     42   uint8_t name_[kMaxNameSize];
     43 };
     44 
     45 
     46 // A set of counters and associated information.  An instance of this
     47 // class is stored directly in the memory-mapped counters file if
     48 // the --map-counters options is used
     49 class CounterCollection {
     50  public:
     51   CounterCollection();
     52   Counter* GetNextCounter();
     53  private:
     54   static const unsigned kMaxCounters = 512;
     55   uint32_t magic_number_;
     56   uint32_t max_counters_;
     57   uint32_t max_name_size_;
     58   uint32_t counters_in_use_;
     59   Counter counters_[kMaxCounters];
     60 };
     61 
     62 struct CStringHasher {
     63   std::size_t operator()(const char* name) const {
     64     size_t h = 0;
     65     size_t c;
     66     while ((c = *name++) != 0) {
     67       h += h << 5;
     68       h += c;
     69     }
     70     return h;
     71   }
     72 };
     73 
     74 typedef std::unordered_map<const char*, Counter*, CStringHasher,
     75                            i::StringEquals>
     76     CounterMap;
     77 
     78 class SourceGroup {
     79  public:
     80   SourceGroup()
     81       : next_semaphore_(0),
     82         done_semaphore_(0),
     83         thread_(nullptr),
     84         argv_(nullptr),
     85         begin_offset_(0),
     86         end_offset_(0) {}
     87 
     88   ~SourceGroup();
     89 
     90   void Begin(char** argv, int offset) {
     91     argv_ = const_cast<const char**>(argv);
     92     begin_offset_ = offset;
     93   }
     94 
     95   void End(int offset) { end_offset_ = offset; }
     96 
     97   void Execute(Isolate* isolate);
     98 
     99   void StartExecuteInThread();
    100   void WaitForThread();
    101   void JoinThread();
    102 
    103  private:
    104   class IsolateThread : public base::Thread {
    105    public:
    106     explicit IsolateThread(SourceGroup* group);
    107 
    108     virtual void Run() {
    109       group_->ExecuteInThread();
    110     }
    111 
    112    private:
    113     SourceGroup* group_;
    114   };
    115 
    116   void ExecuteInThread();
    117 
    118   base::Semaphore next_semaphore_;
    119   base::Semaphore done_semaphore_;
    120   base::Thread* thread_;
    121 
    122   void ExitShell(int exit_code);
    123   Local<String> ReadFile(Isolate* isolate, const char* name);
    124 
    125   const char** argv_;
    126   int begin_offset_;
    127   int end_offset_;
    128 };
    129 
    130 // The backing store of an ArrayBuffer or SharedArrayBuffer, after
    131 // Externalize() has been called on it.
    132 class ExternalizedContents {
    133  public:
    134   explicit ExternalizedContents(const ArrayBuffer::Contents& contents)
    135       : data_(contents.Data()),
    136         length_(contents.ByteLength()),
    137         deleter_(contents.Deleter()),
    138         deleter_data_(contents.DeleterData()) {}
    139   explicit ExternalizedContents(const SharedArrayBuffer::Contents& contents)
    140       : data_(contents.Data()),
    141         length_(contents.ByteLength()),
    142         deleter_(contents.Deleter()),
    143         deleter_data_(contents.DeleterData()) {}
    144   ExternalizedContents(ExternalizedContents&& other) V8_NOEXCEPT
    145       : data_(other.data_),
    146         length_(other.length_),
    147         deleter_(other.deleter_),
    148         deleter_data_(other.deleter_data_) {
    149     other.data_ = nullptr;
    150     other.length_ = 0;
    151     other.deleter_ = nullptr;
    152     other.deleter_data_ = nullptr;
    153   }
    154   ExternalizedContents& operator=(ExternalizedContents&& other) V8_NOEXCEPT {
    155     if (this != &other) {
    156       data_ = other.data_;
    157       length_ = other.length_;
    158       deleter_ = other.deleter_;
    159       deleter_data_ = other.deleter_data_;
    160       other.data_ = nullptr;
    161       other.length_ = 0;
    162       other.deleter_ = nullptr;
    163       other.deleter_data_ = nullptr;
    164     }
    165     return *this;
    166   }
    167   ~ExternalizedContents();
    168 
    169  private:
    170   void* data_;
    171   size_t length_;
    172   ArrayBuffer::Contents::DeleterCallback deleter_;
    173   void* deleter_data_;
    174 
    175   DISALLOW_COPY_AND_ASSIGN(ExternalizedContents);
    176 };
    177 
    178 class SerializationData {
    179  public:
    180   SerializationData() : size_(0) {}
    181 
    182   uint8_t* data() { return data_.get(); }
    183   size_t size() { return size_; }
    184   const std::vector<ArrayBuffer::Contents>& array_buffer_contents() {
    185     return array_buffer_contents_;
    186   }
    187   const std::vector<SharedArrayBuffer::Contents>&
    188   shared_array_buffer_contents() {
    189     return shared_array_buffer_contents_;
    190   }
    191   const std::vector<WasmCompiledModule::TransferrableModule>&
    192   transferrable_modules() {
    193     return transferrable_modules_;
    194   }
    195 
    196  private:
    197   struct DataDeleter {
    198     void operator()(uint8_t* p) const { free(p); }
    199   };
    200 
    201   std::unique_ptr<uint8_t, DataDeleter> data_;
    202   size_t size_;
    203   std::vector<ArrayBuffer::Contents> array_buffer_contents_;
    204   std::vector<SharedArrayBuffer::Contents> shared_array_buffer_contents_;
    205   std::vector<WasmCompiledModule::TransferrableModule> transferrable_modules_;
    206 
    207  private:
    208   friend class Serializer;
    209 
    210   DISALLOW_COPY_AND_ASSIGN(SerializationData);
    211 };
    212 
    213 
    214 class SerializationDataQueue {
    215  public:
    216   void Enqueue(std::unique_ptr<SerializationData> data);
    217   bool Dequeue(std::unique_ptr<SerializationData>* data);
    218   bool IsEmpty();
    219   void Clear();
    220 
    221  private:
    222   base::Mutex mutex_;
    223   std::vector<std::unique_ptr<SerializationData>> data_;
    224 };
    225 
    226 
    227 class Worker {
    228  public:
    229   Worker();
    230   ~Worker();
    231 
    232   // Run the given script on this Worker. This function should only be called
    233   // once, and should only be called by the thread that created the Worker.
    234   void StartExecuteInThread(const char* script);
    235   // Post a message to the worker's incoming message queue. The worker will
    236   // take ownership of the SerializationData.
    237   // This function should only be called by the thread that created the Worker.
    238   void PostMessage(std::unique_ptr<SerializationData> data);
    239   // Synchronously retrieve messages from the worker's outgoing message queue.
    240   // If there is no message in the queue, block until a message is available.
    241   // If there are no messages in the queue and the worker is no longer running,
    242   // return nullptr.
    243   // This function should only be called by the thread that created the Worker.
    244   std::unique_ptr<SerializationData> GetMessage();
    245   // Terminate the worker's event loop. Messages from the worker that have been
    246   // queued can still be read via GetMessage().
    247   // This function can be called by any thread.
    248   void Terminate();
    249   // Terminate and join the thread.
    250   // This function can be called by any thread.
    251   void WaitForThread();
    252 
    253  private:
    254   class WorkerThread : public base::Thread {
    255    public:
    256     explicit WorkerThread(Worker* worker)
    257         : base::Thread(base::Thread::Options("WorkerThread")),
    258           worker_(worker) {}
    259 
    260     virtual void Run() { worker_->ExecuteInThread(); }
    261 
    262    private:
    263     Worker* worker_;
    264   };
    265 
    266   void ExecuteInThread();
    267   static void PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args);
    268 
    269   base::Semaphore in_semaphore_;
    270   base::Semaphore out_semaphore_;
    271   SerializationDataQueue in_queue_;
    272   SerializationDataQueue out_queue_;
    273   base::Thread* thread_;
    274   char* script_;
    275   base::Atomic32 running_;
    276 };
    277 
    278 class PerIsolateData {
    279  public:
    280   explicit PerIsolateData(Isolate* isolate);
    281 
    282   ~PerIsolateData();
    283 
    284   inline static PerIsolateData* Get(Isolate* isolate) {
    285     return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
    286   }
    287 
    288   class RealmScope {
    289    public:
    290     explicit RealmScope(PerIsolateData* data);
    291     ~RealmScope();
    292 
    293    private:
    294     PerIsolateData* data_;
    295   };
    296 
    297   inline void SetTimeout(Local<Function> callback, Local<Context> context);
    298   inline MaybeLocal<Function> GetTimeoutCallback();
    299   inline MaybeLocal<Context> GetTimeoutContext();
    300 
    301   AsyncHooks* GetAsyncHooks() { return async_hooks_wrapper_; }
    302 
    303  private:
    304   friend class Shell;
    305   friend class RealmScope;
    306   Isolate* isolate_;
    307   int realm_count_;
    308   int realm_current_;
    309   int realm_switch_;
    310   Global<Context>* realms_;
    311   Global<Value> realm_shared_;
    312   std::queue<Global<Function>> set_timeout_callbacks_;
    313   std::queue<Global<Context>> set_timeout_contexts_;
    314   AsyncHooks* async_hooks_wrapper_;
    315 
    316   int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
    317                         int arg_offset);
    318   int RealmFind(Local<Context> context);
    319 };
    320 
    321 class ShellOptions {
    322  public:
    323   enum CodeCacheOptions {
    324     kNoProduceCache,
    325     kProduceCache,
    326     kProduceCacheAfterExecute
    327   };
    328 
    329   ShellOptions()
    330       : send_idle_notification(false),
    331         invoke_weak_callbacks(false),
    332         omit_quit(false),
    333         wait_for_wasm(true),
    334         stress_opt(false),
    335         stress_deopt(false),
    336         stress_runs(1),
    337         interactive_shell(false),
    338         test_shell(false),
    339         expected_to_throw(false),
    340         mock_arraybuffer_allocator(false),
    341         enable_inspector(false),
    342         num_isolates(1),
    343         compile_options(v8::ScriptCompiler::kNoCompileOptions),
    344         stress_background_compile(false),
    345         code_cache_options(CodeCacheOptions::kNoProduceCache),
    346         isolate_sources(nullptr),
    347         icu_data_file(nullptr),
    348         natives_blob(nullptr),
    349         snapshot_blob(nullptr),
    350         trace_enabled(false),
    351         trace_path(nullptr),
    352         trace_config(nullptr),
    353         lcov_file(nullptr),
    354         disable_in_process_stack_traces(false),
    355         read_from_tcp_port(-1) {}
    356 
    357   ~ShellOptions() {
    358     delete[] isolate_sources;
    359   }
    360 
    361   bool send_idle_notification;
    362   bool invoke_weak_callbacks;
    363   bool omit_quit;
    364   bool wait_for_wasm;
    365   bool stress_opt;
    366   bool stress_deopt;
    367   int stress_runs;
    368   bool interactive_shell;
    369   bool test_shell;
    370   bool expected_to_throw;
    371   bool mock_arraybuffer_allocator;
    372   bool enable_inspector;
    373   int num_isolates;
    374   v8::ScriptCompiler::CompileOptions compile_options;
    375   bool stress_background_compile;
    376   CodeCacheOptions code_cache_options;
    377   SourceGroup* isolate_sources;
    378   const char* icu_data_file;
    379   const char* natives_blob;
    380   const char* snapshot_blob;
    381   bool trace_enabled;
    382   const char* trace_path;
    383   const char* trace_config;
    384   const char* lcov_file;
    385   bool disable_in_process_stack_traces;
    386   int read_from_tcp_port;
    387   bool enable_os_system = false;
    388   bool quiet_load = false;
    389   int thread_pool_size = 0;
    390 };
    391 
    392 class Shell : public i::AllStatic {
    393  public:
    394   enum PrintResult : bool { kPrintResult = true, kNoPrintResult = false };
    395   enum ReportExceptions : bool {
    396     kReportExceptions = true,
    397     kNoReportExceptions = false
    398   };
    399   enum ProcessMessageQueue : bool {
    400     kProcessMessageQueue = true,
    401     kNoProcessMessageQueue = false
    402   };
    403 
    404   static bool ExecuteString(Isolate* isolate, Local<String> source,
    405                             Local<Value> name, PrintResult print_result,
    406                             ReportExceptions report_exceptions,
    407                             ProcessMessageQueue process_message_queue);
    408   static bool ExecuteModule(Isolate* isolate, const char* file_name);
    409   static void ReportException(Isolate* isolate, TryCatch* try_catch);
    410   static Local<String> ReadFile(Isolate* isolate, const char* name);
    411   static Local<Context> CreateEvaluationContext(Isolate* isolate);
    412   static int RunMain(Isolate* isolate, int argc, char* argv[], bool last_run);
    413   static int Main(int argc, char* argv[]);
    414   static void Exit(int exit_code);
    415   static void OnExit(Isolate* isolate);
    416   static void CollectGarbage(Isolate* isolate);
    417   static bool EmptyMessageQueues(Isolate* isolate);
    418   static void CompleteMessageLoop(Isolate* isolate);
    419 
    420   static std::unique_ptr<SerializationData> SerializeValue(
    421       Isolate* isolate, Local<Value> value, Local<Value> transfer);
    422   static MaybeLocal<Value> DeserializeValue(
    423       Isolate* isolate, std::unique_ptr<SerializationData> data);
    424   static void CleanupWorkers();
    425   static int* LookupCounter(const char* name);
    426   static void* CreateHistogram(const char* name,
    427                                int min,
    428                                int max,
    429                                size_t buckets);
    430   static void AddHistogramSample(void* histogram, int sample);
    431   static void MapCounters(v8::Isolate* isolate, const char* name);
    432 
    433   static void PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args);
    434 
    435   static void RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args);
    436   static void RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args);
    437   static void RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args);
    438   static void RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args);
    439   static void RealmNavigate(const v8::FunctionCallbackInfo<v8::Value>& args);
    440   static void RealmCreateAllowCrossRealmAccess(
    441       const v8::FunctionCallbackInfo<v8::Value>& args);
    442   static void RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args);
    443   static void RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args);
    444   static void RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args);
    445   static void RealmSharedGet(Local<String> property,
    446                              const  PropertyCallbackInfo<Value>& info);
    447   static void RealmSharedSet(Local<String> property,
    448                              Local<Value> value,
    449                              const  PropertyCallbackInfo<void>& info);
    450 
    451   static void AsyncHooksCreateHook(
    452       const v8::FunctionCallbackInfo<v8::Value>& args);
    453   static void AsyncHooksExecutionAsyncId(
    454       const v8::FunctionCallbackInfo<v8::Value>& args);
    455   static void AsyncHooksTriggerAsyncId(
    456       const v8::FunctionCallbackInfo<v8::Value>& args);
    457 
    458   static void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
    459   static void PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args);
    460   static void Write(const v8::FunctionCallbackInfo<v8::Value>& args);
    461   static void WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args);
    462   static void NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args);
    463   static void QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args);
    464   static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
    465   static void Version(const v8::FunctionCallbackInfo<v8::Value>& args);
    466   static void Read(const v8::FunctionCallbackInfo<v8::Value>& args);
    467   static void ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args);
    468   static Local<String> ReadFromStdin(Isolate* isolate);
    469   static void ReadLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
    470     args.GetReturnValue().Set(ReadFromStdin(args.GetIsolate()));
    471   }
    472   static void Load(const v8::FunctionCallbackInfo<v8::Value>& args);
    473   static void SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args);
    474   static void WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args);
    475   static void WorkerPostMessage(
    476       const v8::FunctionCallbackInfo<v8::Value>& args);
    477   static void WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
    478   static void WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args);
    479   // The OS object on the global object contains methods for performing
    480   // operating system calls:
    481   //
    482   // os.system("program_name", ["arg1", "arg2", ...], timeout1, timeout2) will
    483   // run the command, passing the arguments to the program.  The standard output
    484   // of the program will be picked up and returned as a multiline string.  If
    485   // timeout1 is present then it should be a number.  -1 indicates no timeout
    486   // and a positive number is used as a timeout in milliseconds that limits the
    487   // time spent waiting between receiving output characters from the program.
    488   // timeout2, if present, should be a number indicating the limit in
    489   // milliseconds on the total running time of the program.  Exceptions are
    490   // thrown on timeouts or other errors or if the exit status of the program
    491   // indicates an error.
    492   //
    493   // os.chdir(dir) changes directory to the given directory.  Throws an
    494   // exception/ on error.
    495   //
    496   // os.setenv(variable, value) sets an environment variable.  Repeated calls to
    497   // this method leak memory due to the API of setenv in the standard C library.
    498   //
    499   // os.umask(alue) calls the umask system call and returns the old umask.
    500   //
    501   // os.mkdirp(name, mask) creates a directory.  The mask (if present) is anded
    502   // with the current umask.  Intermediate directories are created if necessary.
    503   // An exception is not thrown if the directory already exists.  Analogous to
    504   // the "mkdir -p" command.
    505   static void System(const v8::FunctionCallbackInfo<v8::Value>& args);
    506   static void ChangeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
    507   static void SetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
    508   static void UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
    509   static void SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args);
    510   static void MakeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
    511   static void RemoveDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
    512   static MaybeLocal<Promise> HostImportModuleDynamically(
    513       Local<Context> context, Local<ScriptOrModule> referrer,
    514       Local<String> specifier);
    515   static void HostInitializeImportMetaObject(Local<Context> context,
    516                                              Local<Module> module,
    517                                              Local<Object> meta);
    518 
    519   // Data is of type DynamicImportData*. We use void* here to be able
    520   // to conform with MicrotaskCallback interface and enqueue this
    521   // function in the microtask queue.
    522   static void DoHostImportModuleDynamically(void* data);
    523   static void AddOSMethods(v8::Isolate* isolate,
    524                            Local<ObjectTemplate> os_template);
    525 
    526   static const char* kPrompt;
    527   static ShellOptions options;
    528   static ArrayBuffer::Allocator* array_buffer_allocator;
    529 
    530   static void SetWaitUntilDone(Isolate* isolate, bool value);
    531 
    532   static char* ReadCharsFromTcpPort(const char* name, int* size_out);
    533 
    534   static void set_script_executed() { script_executed_.store(true); }
    535   static bool use_interactive_shell() {
    536     return (options.interactive_shell || !script_executed_.load()) &&
    537            !options.test_shell;
    538   }
    539 
    540  private:
    541   static Global<Context> evaluation_context_;
    542   static base::OnceType quit_once_;
    543   static Global<Function> stringify_function_;
    544   static CounterMap* counter_map_;
    545   // We statically allocate a set of local counters to be used if we
    546   // don't want to store the stats in a memory-mapped file
    547   static CounterCollection local_counters_;
    548   static CounterCollection* counters_;
    549   static base::OS::MemoryMappedFile* counters_file_;
    550   static base::LazyMutex context_mutex_;
    551   static const base::TimeTicks kInitialTicks;
    552 
    553   static base::LazyMutex workers_mutex_;  // Guards the following members.
    554   static bool allow_new_workers_;
    555   static std::vector<Worker*> workers_;
    556   static std::vector<ExternalizedContents> externalized_contents_;
    557 
    558   // Multiple isolates may update this flag concurrently.
    559   static std::atomic<bool> script_executed_;
    560 
    561   static void WriteIgnitionDispatchCountersFile(v8::Isolate* isolate);
    562   // Append LCOV coverage data to file.
    563   static void WriteLcovData(v8::Isolate* isolate, const char* file);
    564   static Counter* GetCounter(const char* name, bool is_histogram);
    565   static Local<String> Stringify(Isolate* isolate, Local<Value> value);
    566   static void Initialize(Isolate* isolate);
    567   static void RunShell(Isolate* isolate);
    568   static bool SetOptions(int argc, char* argv[]);
    569   static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate);
    570   static MaybeLocal<Context> CreateRealm(
    571       const v8::FunctionCallbackInfo<v8::Value>& args, int index,
    572       v8::MaybeLocal<Value> global_object);
    573   static void DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
    574                            int index);
    575   static MaybeLocal<Module> FetchModuleTree(v8::Local<v8::Context> context,
    576                                             const std::string& file_name);
    577   static ScriptCompiler::CachedData* LookupCodeCache(Isolate* isolate,
    578                                                      Local<Value> name);
    579   static void StoreInCodeCache(Isolate* isolate, Local<Value> name,
    580                                const ScriptCompiler::CachedData* data);
    581   // We may have multiple isolates running concurrently, so the access to
    582   // the isolate_status_ needs to be concurrency-safe.
    583   static base::LazyMutex isolate_status_lock_;
    584   static std::map<Isolate*, bool> isolate_status_;
    585 
    586   static base::LazyMutex cached_code_mutex_;
    587   static std::map<std::string, std::unique_ptr<ScriptCompiler::CachedData>>
    588       cached_code_map_;
    589 };
    590 
    591 
    592 }  // namespace v8
    593 
    594 
    595 #endif  // V8_D8_H_
    596