Line data Source code
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 : #include <errno.h>
6 : #include <stdlib.h>
7 : #include <string.h>
8 : #include <sys/stat.h>
9 :
10 : #include <algorithm>
11 : #include <fstream>
12 : #include <unordered_map>
13 : #include <utility>
14 : #include <vector>
15 :
16 : #ifdef ENABLE_VTUNE_JIT_INTERFACE
17 : #include "src/third_party/vtune/v8-vtune.h"
18 : #endif
19 :
20 : #include "src/d8-console.h"
21 : #include "src/d8.h"
22 : #include "src/ostreams.h"
23 :
24 : #include "include/libplatform/libplatform.h"
25 : #include "include/libplatform/v8-tracing.h"
26 : #include "include/v8-inspector.h"
27 : #include "src/api.h"
28 : #include "src/base/cpu.h"
29 : #include "src/base/logging.h"
30 : #include "src/base/platform/platform.h"
31 : #include "src/base/platform/time.h"
32 : #include "src/base/sys-info.h"
33 : #include "src/basic-block-profiler.h"
34 : #include "src/debug/debug-interface.h"
35 : #include "src/interpreter/interpreter.h"
36 : #include "src/msan.h"
37 : #include "src/objects-inl.h"
38 : #include "src/objects.h"
39 : #include "src/snapshot/natives.h"
40 : #include "src/trap-handler/trap-handler.h"
41 : #include "src/utils.h"
42 : #include "src/v8.h"
43 :
44 : #if defined(LEAK_SANITIZER)
45 : #include <sanitizer/lsan_interface.h>
46 : #endif
47 :
48 : #if !defined(_WIN32) && !defined(_WIN64)
49 : #include <unistd.h> // NOLINT
50 : #else
51 : #include <windows.h> // NOLINT
52 : #if defined(_MSC_VER)
53 : #include <crtdbg.h> // NOLINT
54 : #endif // defined(_MSC_VER)
55 : #endif // !defined(_WIN32) && !defined(_WIN64)
56 :
57 : #ifndef DCHECK
58 : #define DCHECK(condition) assert(condition)
59 : #endif
60 :
61 : #ifndef CHECK
62 : #define CHECK(condition) assert(condition)
63 : #endif
64 :
65 : namespace v8 {
66 :
67 : namespace {
68 :
69 : const int MB = 1024 * 1024;
70 : const int kMaxWorkers = 50;
71 : const int kMaxSerializerMemoryUsage = 1 * MB; // Arbitrary maximum for testing.
72 :
73 : #define USE_VM 1
74 : #define VM_THRESHOLD 65536
75 : // TODO(titzer): allocations should fail if >= 2gb because of
76 : // array buffers storing the lengths as a SMI internally.
77 : #define TWO_GB (2u * 1024u * 1024u * 1024u)
78 :
79 : // Forwards memory reservation and protection functions to the V8 default
80 : // allocator. Used by ShellArrayBufferAllocator and MockArrayBufferAllocator.
81 107132 : class ArrayBufferAllocatorBase : public v8::ArrayBuffer::Allocator {
82 : std::unique_ptr<Allocator> allocator_ =
83 : std::unique_ptr<Allocator>(NewDefaultAllocator());
84 :
85 : public:
86 650 : void* Reserve(size_t length) override { return allocator_->Reserve(length); }
87 :
88 : void Free(void*, size_t) override = 0;
89 :
90 234088 : void Free(void* data, size_t length, AllocationMode mode) override {
91 234088 : switch (mode) {
92 : case AllocationMode::kNormal: {
93 233765 : return Free(data, length);
94 : }
95 : case AllocationMode::kReservation: {
96 323 : return allocator_->Free(data, length, mode);
97 : }
98 : }
99 : }
100 :
101 475 : void SetProtection(void* data, size_t length,
102 : Protection protection) override {
103 475 : allocator_->SetProtection(data, length, protection);
104 475 : }
105 : };
106 :
107 53566 : class ShellArrayBufferAllocator : public ArrayBufferAllocatorBase {
108 : public:
109 222581 : void* Allocate(size_t length) override {
110 : #if USE_VM
111 222581 : if (RoundToPageSize(&length)) {
112 5045 : void* data = VirtualMemoryAllocate(length);
113 : #if DEBUG
114 : if (data) {
115 : // In debug mode, check the memory is zero-initialized.
116 : size_t limit = length / sizeof(uint64_t);
117 : uint64_t* ptr = reinterpret_cast<uint64_t*>(data);
118 : for (size_t i = 0; i < limit; i++) {
119 : DCHECK_EQ(0u, ptr[i]);
120 : }
121 : }
122 : #endif
123 5045 : return data;
124 : }
125 : #endif
126 217536 : void* data = AllocateUninitialized(length);
127 435072 : return data == nullptr ? data : memset(data, 0, length);
128 : }
129 230792 : void* AllocateUninitialized(size_t length) override {
130 : #if USE_VM
131 230792 : if (RoundToPageSize(&length)) return VirtualMemoryAllocate(length);
132 : #endif
133 : // Work around for GCC bug on AIX
134 : // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79839
135 : #if V8_OS_AIX && _LINUX_SOURCE_COMPAT
136 : return __linux_malloc(length);
137 : #else
138 230792 : return malloc(length);
139 : #endif
140 : }
141 : using ArrayBufferAllocatorBase::Free;
142 235897 : void Free(void* data, size_t length) override {
143 : #if USE_VM
144 235897 : if (RoundToPageSize(&length)) {
145 5047 : base::OS::ReleaseRegion(data, length);
146 240976 : return;
147 : }
148 : #endif
149 230882 : free(data);
150 : }
151 : // If {length} is at least {VM_THRESHOLD}, round up to next page size
152 : // and return {true}. Otherwise return {false}.
153 689269 : bool RoundToPageSize(size_t* length) {
154 689269 : const size_t kPageSize = base::OS::CommitPageSize();
155 689266 : if (*length >= VM_THRESHOLD && *length < TWO_GB) {
156 10092 : *length = ((*length + kPageSize - 1) / kPageSize) * kPageSize;
157 : return true;
158 : }
159 : return false;
160 : }
161 : #if USE_VM
162 5045 : void* VirtualMemoryAllocate(size_t length) {
163 5045 : void* data = base::OS::ReserveRegion(length, nullptr);
164 5045 : if (data && !base::OS::CommitRegion(data, length, false)) {
165 0 : base::OS::ReleaseRegion(data, length);
166 : return nullptr;
167 : }
168 : #if defined(LEAK_SANITIZER)
169 : __lsan_register_root_region(data, length);
170 : #endif
171 : MSAN_MEMORY_IS_INITIALIZED(data, length);
172 : return data;
173 : }
174 : #endif
175 : };
176 :
177 53566 : class MockArrayBufferAllocator : public ArrayBufferAllocatorBase {
178 : const size_t kAllocationLimit = 10 * MB;
179 : size_t get_actual_length(size_t length) const {
180 132 : return length > kAllocationLimit ? base::OS::CommitPageSize() : length;
181 : }
182 :
183 : public:
184 44 : void* Allocate(size_t length) override {
185 : const size_t actual_length = get_actual_length(length);
186 44 : void* data = AllocateUninitialized(actual_length);
187 88 : return data == nullptr ? data : memset(data, 0, actual_length);
188 : }
189 44 : void* AllocateUninitialized(size_t length) override {
190 44 : return malloc(get_actual_length(length));
191 : }
192 44 : void Free(void* p, size_t) override { free(p); }
193 44 : void Free(void* data, size_t length, AllocationMode mode) override {
194 44 : ArrayBufferAllocatorBase::Free(data, get_actual_length(length), mode);
195 44 : }
196 0 : void* Reserve(size_t length) override {
197 0 : return ArrayBufferAllocatorBase::Reserve(get_actual_length(length));
198 : }
199 : };
200 :
201 : // Predictable v8::Platform implementation. Background tasks and idle tasks are
202 : // disallowed, and the time reported by {MonotonicallyIncreasingTime} is
203 : // deterministic.
204 : class PredictablePlatform : public Platform {
205 : public:
206 : explicit PredictablePlatform(std::unique_ptr<Platform> platform)
207 : : platform_(std::move(platform)) {
208 : DCHECK_NOT_NULL(platform_);
209 : }
210 :
211 : void CallOnBackgroundThread(Task* task,
212 : ExpectedRuntime expected_runtime) override {
213 : // It's not defined when background tasks are being executed, so we can just
214 : // execute them right away.
215 : task->Run();
216 : delete task;
217 : }
218 :
219 : void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
220 : platform_->CallOnForegroundThread(isolate, task);
221 : }
222 :
223 : void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
224 : double delay_in_seconds) override {
225 : platform_->CallDelayedOnForegroundThread(isolate, task, delay_in_seconds);
226 : }
227 :
228 : void CallIdleOnForegroundThread(Isolate* isolate, IdleTask* task) override {
229 : UNREACHABLE();
230 : }
231 :
232 : bool IdleTasksEnabled(Isolate* isolate) override { return false; }
233 :
234 : double MonotonicallyIncreasingTime() override {
235 : return synthetic_time_in_sec_ += 0.00001;
236 : }
237 :
238 : double CurrentClockTimeMillis() override {
239 : return MonotonicallyIncreasingTime() * base::Time::kMillisecondsPerSecond;
240 : }
241 :
242 : v8::TracingController* GetTracingController() override {
243 : return platform_->GetTracingController();
244 : }
245 :
246 : Platform* platform() const { return platform_.get(); }
247 :
248 : private:
249 : double synthetic_time_in_sec_ = 0.0;
250 : std::unique_ptr<Platform> platform_;
251 :
252 : DISALLOW_COPY_AND_ASSIGN(PredictablePlatform);
253 : };
254 :
255 : v8::Platform* g_platform = nullptr;
256 :
257 : v8::Platform* GetDefaultPlatform() {
258 : return i::FLAG_verify_predictable
259 : ? static_cast<PredictablePlatform*>(g_platform)->platform()
260 192676 : : g_platform;
261 : }
262 :
263 6537 : static Local<Value> Throw(Isolate* isolate, const char* message) {
264 : return isolate->ThrowException(
265 : String::NewFromUtf8(isolate, message, NewStringType::kNormal)
266 13074 : .ToLocalChecked());
267 : }
268 :
269 1137 : Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
270 1137 : if (object->InternalFieldCount() != 1) {
271 0 : Throw(isolate, "this is not a Worker");
272 0 : return nullptr;
273 : }
274 :
275 : Worker* worker =
276 : static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
277 1137 : if (worker == nullptr) {
278 10 : Throw(isolate, "Worker is defunct because main thread is terminating");
279 10 : return nullptr;
280 : }
281 :
282 : return worker;
283 : }
284 :
285 :
286 : } // namespace
287 :
288 : namespace tracing {
289 :
290 : namespace {
291 :
292 : // String options that can be used to initialize TraceOptions.
293 : const char kRecordUntilFull[] = "record-until-full";
294 : const char kRecordContinuously[] = "record-continuously";
295 : const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible";
296 :
297 : const char kRecordModeParam[] = "record_mode";
298 : const char kEnableSystraceParam[] = "enable_systrace";
299 : const char kEnableArgumentFilterParam[] = "enable_argument_filter";
300 : const char kIncludedCategoriesParam[] = "included_categories";
301 :
302 : class TraceConfigParser {
303 : public:
304 0 : static void FillTraceConfig(v8::Isolate* isolate,
305 : platform::tracing::TraceConfig* trace_config,
306 : const char* json_str) {
307 0 : HandleScope outer_scope(isolate);
308 0 : Local<Context> context = Context::New(isolate);
309 : Context::Scope context_scope(context);
310 0 : HandleScope inner_scope(isolate);
311 :
312 : Local<String> source =
313 : String::NewFromUtf8(isolate, json_str, NewStringType::kNormal)
314 0 : .ToLocalChecked();
315 0 : Local<Value> result = JSON::Parse(context, source).ToLocalChecked();
316 0 : Local<v8::Object> trace_config_object = Local<v8::Object>::Cast(result);
317 :
318 : trace_config->SetTraceRecordMode(
319 0 : GetTraceRecordMode(isolate, context, trace_config_object));
320 0 : if (GetBoolean(isolate, context, trace_config_object,
321 : kEnableSystraceParam)) {
322 : trace_config->EnableSystrace();
323 : }
324 0 : if (GetBoolean(isolate, context, trace_config_object,
325 : kEnableArgumentFilterParam)) {
326 : trace_config->EnableArgumentFilter();
327 : }
328 : UpdateIncludedCategoriesList(isolate, context, trace_config_object,
329 0 : trace_config);
330 0 : }
331 :
332 : private:
333 0 : static bool GetBoolean(v8::Isolate* isolate, Local<Context> context,
334 : Local<v8::Object> object, const char* property) {
335 0 : Local<Value> value = GetValue(isolate, context, object, property);
336 0 : if (value->IsNumber()) {
337 0 : Local<Boolean> v8_boolean = value->ToBoolean(context).ToLocalChecked();
338 0 : return v8_boolean->Value();
339 : }
340 : return false;
341 : }
342 :
343 0 : static int UpdateIncludedCategoriesList(
344 : v8::Isolate* isolate, Local<Context> context, Local<v8::Object> object,
345 : platform::tracing::TraceConfig* trace_config) {
346 : Local<Value> value =
347 0 : GetValue(isolate, context, object, kIncludedCategoriesParam);
348 0 : if (value->IsArray()) {
349 : Local<Array> v8_array = Local<Array>::Cast(value);
350 0 : for (int i = 0, length = v8_array->Length(); i < length; ++i) {
351 0 : Local<Value> v = v8_array->Get(context, i)
352 0 : .ToLocalChecked()
353 : ->ToString(context)
354 0 : .ToLocalChecked();
355 0 : String::Utf8Value str(isolate, v->ToString(context).ToLocalChecked());
356 0 : trace_config->AddIncludedCategory(*str);
357 0 : }
358 0 : return v8_array->Length();
359 : }
360 : return 0;
361 : }
362 :
363 0 : static platform::tracing::TraceRecordMode GetTraceRecordMode(
364 : v8::Isolate* isolate, Local<Context> context, Local<v8::Object> object) {
365 0 : Local<Value> value = GetValue(isolate, context, object, kRecordModeParam);
366 0 : if (value->IsString()) {
367 0 : Local<String> v8_string = value->ToString(context).ToLocalChecked();
368 0 : String::Utf8Value str(isolate, v8_string);
369 0 : if (strcmp(kRecordUntilFull, *str) == 0) {
370 0 : return platform::tracing::TraceRecordMode::RECORD_UNTIL_FULL;
371 0 : } else if (strcmp(kRecordContinuously, *str) == 0) {
372 : return platform::tracing::TraceRecordMode::RECORD_CONTINUOUSLY;
373 0 : } else if (strcmp(kRecordAsMuchAsPossible, *str) == 0) {
374 : return platform::tracing::TraceRecordMode::RECORD_AS_MUCH_AS_POSSIBLE;
375 0 : }
376 : }
377 : return platform::tracing::TraceRecordMode::RECORD_UNTIL_FULL;
378 : }
379 :
380 0 : static Local<Value> GetValue(v8::Isolate* isolate, Local<Context> context,
381 : Local<v8::Object> object, const char* property) {
382 : Local<String> v8_str =
383 : String::NewFromUtf8(isolate, property, NewStringType::kNormal)
384 0 : .ToLocalChecked();
385 0 : return object->Get(context, v8_str).ToLocalChecked();
386 : }
387 : };
388 :
389 : } // namespace
390 :
391 0 : static platform::tracing::TraceConfig* CreateTraceConfigFromJSON(
392 : v8::Isolate* isolate, const char* json_str) {
393 : platform::tracing::TraceConfig* trace_config =
394 0 : new platform::tracing::TraceConfig();
395 0 : TraceConfigParser::FillTraceConfig(isolate, trace_config, json_str);
396 0 : return trace_config;
397 : }
398 :
399 : } // namespace tracing
400 :
401 : class PerIsolateData {
402 : public:
403 27170 : explicit PerIsolateData(Isolate* isolate)
404 81510 : : isolate_(isolate), realms_(nullptr) {
405 : isolate->SetData(0, this);
406 27170 : }
407 :
408 27170 : ~PerIsolateData() {
409 27170 : isolate_->SetData(0, nullptr); // Not really needed, just to be sure...
410 27170 : }
411 :
412 : inline static PerIsolateData* Get(Isolate* isolate) {
413 : return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
414 : }
415 :
416 : class RealmScope {
417 : public:
418 : explicit RealmScope(PerIsolateData* data);
419 : ~RealmScope();
420 : private:
421 : PerIsolateData* data_;
422 : };
423 :
424 60 : inline void SetTimeout(Local<Function> callback, Local<Context> context) {
425 60 : set_timeout_callbacks_.emplace(isolate_, callback);
426 : set_timeout_contexts_.emplace(isolate_, context);
427 60 : }
428 :
429 148243 : inline MaybeLocal<Function> GetTimeoutCallback() {
430 148243 : if (set_timeout_callbacks_.empty()) return MaybeLocal<Function>();
431 60 : Local<Function> result = set_timeout_callbacks_.front().Get(isolate_);
432 : set_timeout_callbacks_.pop();
433 60 : return result;
434 : }
435 :
436 60 : inline MaybeLocal<Context> GetTimeoutContext() {
437 60 : if (set_timeout_contexts_.empty()) return MaybeLocal<Context>();
438 60 : Local<Context> result = set_timeout_contexts_.front().Get(isolate_);
439 : set_timeout_contexts_.pop();
440 60 : return result;
441 : }
442 :
443 : private:
444 : friend class Shell;
445 : friend class RealmScope;
446 : Isolate* isolate_;
447 : int realm_count_;
448 : int realm_current_;
449 : int realm_switch_;
450 : Global<Context>* realms_;
451 : Global<Value> realm_shared_;
452 : std::queue<Global<Function>> set_timeout_callbacks_;
453 : std::queue<Global<Context>> set_timeout_contexts_;
454 :
455 : int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
456 : int arg_offset);
457 : int RealmFind(Local<Context> context);
458 : };
459 :
460 0 : class ExternalOwningOneByteStringResource
461 : : public String::ExternalOneByteStringResource {
462 : public:
463 : ExternalOwningOneByteStringResource() : length_(0) {}
464 : ExternalOwningOneByteStringResource(std::unique_ptr<const char[]> data,
465 : size_t length)
466 0 : : data_(std::move(data)), length_(length) {}
467 0 : const char* data() const override { return data_.get(); }
468 0 : size_t length() const override { return length_; }
469 :
470 : private:
471 : std::unique_ptr<const char[]> data_;
472 : size_t length_;
473 : };
474 :
475 : CounterMap* Shell::counter_map_;
476 : base::OS::MemoryMappedFile* Shell::counters_file_ = nullptr;
477 : CounterCollection Shell::local_counters_;
478 : CounterCollection* Shell::counters_ = &local_counters_;
479 : base::LazyMutex Shell::context_mutex_;
480 26783 : const base::TimeTicks Shell::kInitialTicks =
481 : base::TimeTicks::HighResolutionNow();
482 26783 : Global<Function> Shell::stringify_function_;
483 : base::LazyMutex Shell::workers_mutex_;
484 : bool Shell::allow_new_workers_ = true;
485 26783 : std::vector<Worker*> Shell::workers_;
486 26783 : std::vector<ExternalizedContents> Shell::externalized_contents_;
487 : base::LazyMutex Shell::isolate_status_lock_;
488 26783 : std::map<v8::Isolate*, bool> Shell::isolate_status_;
489 :
490 26783 : Global<Context> Shell::evaluation_context_;
491 : ArrayBuffer::Allocator* Shell::array_buffer_allocator;
492 26783 : ShellOptions Shell::options;
493 : base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
494 :
495 0 : bool CounterMap::Match(void* key1, void* key2) {
496 : const char* name1 = reinterpret_cast<const char*>(key1);
497 : const char* name2 = reinterpret_cast<const char*>(key2);
498 0 : return strcmp(name1, name2) == 0;
499 : }
500 :
501 :
502 225 : ScriptCompiler::CachedData* CompileForCachedData(
503 : Local<String> source, Local<Value> name,
504 : ScriptCompiler::CompileOptions compile_options) {
505 225 : int source_length = source->Length();
506 225 : uint16_t* source_buffer = new uint16_t[source_length];
507 225 : source->Write(source_buffer, 0, source_length);
508 : int name_length = 0;
509 : uint16_t* name_buffer = nullptr;
510 225 : if (name->IsString()) {
511 : Local<String> name_string = Local<String>::Cast(name);
512 225 : name_length = name_string->Length();
513 225 : name_buffer = new uint16_t[name_length];
514 225 : name_string->Write(name_buffer, 0, name_length);
515 : }
516 : Isolate::CreateParams create_params;
517 225 : create_params.array_buffer_allocator = Shell::array_buffer_allocator;
518 225 : Isolate* temp_isolate = Isolate::New(create_params);
519 : temp_isolate->SetHostImportModuleDynamicallyCallback(
520 225 : Shell::HostImportModuleDynamically);
521 : temp_isolate->SetHostInitializeImportMetaObjectCallback(
522 225 : Shell::HostInitializeImportMetaObject);
523 : ScriptCompiler::CachedData* result = nullptr;
524 : {
525 : Isolate::Scope isolate_scope(temp_isolate);
526 450 : HandleScope handle_scope(temp_isolate);
527 450 : Context::Scope context_scope(Context::New(temp_isolate));
528 : Local<String> source_copy =
529 : v8::String::NewFromTwoByte(temp_isolate, source_buffer,
530 : v8::NewStringType::kNormal, source_length)
531 225 : .ToLocalChecked();
532 : Local<Value> name_copy;
533 225 : if (name_buffer) {
534 : name_copy =
535 : v8::String::NewFromTwoByte(temp_isolate, name_buffer,
536 : v8::NewStringType::kNormal, name_length)
537 225 : .ToLocalChecked();
538 : } else {
539 : name_copy = v8::Undefined(temp_isolate);
540 : }
541 : ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy));
542 225 : if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source,
543 : compile_options)
544 675 : .IsEmpty() &&
545 225 : script_source.GetCachedData()) {
546 215 : int length = script_source.GetCachedData()->length;
547 215 : uint8_t* cache = new uint8_t[length];
548 215 : memcpy(cache, script_source.GetCachedData()->data, length);
549 : result = new ScriptCompiler::CachedData(
550 215 : cache, length, ScriptCompiler::CachedData::BufferOwned);
551 : }
552 : }
553 225 : temp_isolate->Dispose();
554 225 : delete[] source_buffer;
555 225 : delete[] name_buffer;
556 225 : return result;
557 : }
558 :
559 :
560 : // Compile a string within the current v8 context.
561 104366 : MaybeLocal<Script> Shell::CompileString(
562 : Isolate* isolate, Local<String> source, Local<Value> name,
563 : ScriptCompiler::CompileOptions compile_options) {
564 104366 : Local<Context> context(isolate->GetCurrentContext());
565 : ScriptOrigin origin(name);
566 104366 : if (compile_options == ScriptCompiler::kNoCompileOptions) {
567 : ScriptCompiler::Source script_source(source, origin);
568 104141 : return ScriptCompiler::Compile(context, &script_source, compile_options);
569 : }
570 :
571 : ScriptCompiler::CachedData* data =
572 225 : CompileForCachedData(source, name, compile_options);
573 : ScriptCompiler::Source cached_source(source, origin, data);
574 225 : if (compile_options == ScriptCompiler::kProduceCodeCache) {
575 : compile_options = ScriptCompiler::kConsumeCodeCache;
576 0 : } else if (compile_options == ScriptCompiler::kProduceParserCache) {
577 : compile_options = ScriptCompiler::kConsumeParserCache;
578 : } else {
579 : DCHECK(false); // A new compile option?
580 : }
581 225 : if (data == nullptr) compile_options = ScriptCompiler::kNoCompileOptions;
582 : MaybeLocal<Script> result =
583 225 : ScriptCompiler::Compile(context, &cached_source, compile_options);
584 225 : CHECK(data == nullptr || !data->rejected);
585 225 : return result;
586 : }
587 :
588 :
589 : // Executes a string within the current v8 context.
590 104366 : bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
591 : Local<Value> name, bool print_result,
592 : bool report_exceptions) {
593 104366 : HandleScope handle_scope(isolate);
594 208732 : TryCatch try_catch(isolate);
595 104366 : try_catch.SetVerbose(true);
596 :
597 : MaybeLocal<Value> maybe_result;
598 : {
599 : PerIsolateData* data = PerIsolateData::Get(isolate);
600 : Local<Context> realm =
601 104366 : Local<Context>::New(isolate, data->realms_[data->realm_current_]);
602 : Context::Scope context_scope(realm);
603 : Local<Script> script;
604 208732 : if (!Shell::CompileString(isolate, source, name, options.compile_options)
605 104366 : .ToLocal(&script)) {
606 : // Print errors that happened during compilation.
607 1341 : if (report_exceptions) ReportException(isolate, &try_catch);
608 : return false;
609 : }
610 103025 : maybe_result = script->Run(realm);
611 103025 : EmptyMessageQueues(isolate);
612 103025 : data->realm_current_ = data->realm_switch_;
613 : }
614 : Local<Value> result;
615 103025 : if (!maybe_result.ToLocal(&result)) {
616 : DCHECK(try_catch.HasCaught());
617 : // Print errors that happened during execution.
618 6280 : if (report_exceptions) ReportException(isolate, &try_catch);
619 : return false;
620 : }
621 : DCHECK(!try_catch.HasCaught());
622 96745 : if (print_result) {
623 0 : if (options.test_shell) {
624 0 : if (!result->IsUndefined()) {
625 : // If all went well and the result wasn't undefined then print
626 : // the returned value.
627 0 : v8::String::Utf8Value str(isolate, result);
628 0 : fwrite(*str, sizeof(**str), str.length(), stdout);
629 0 : printf("\n");
630 : }
631 : } else {
632 0 : v8::String::Utf8Value str(isolate, Stringify(isolate, result));
633 0 : fwrite(*str, sizeof(**str), str.length(), stdout);
634 0 : printf("\n");
635 : }
636 : }
637 104366 : return true;
638 : }
639 :
640 : namespace {
641 :
642 2298 : std::string ToSTLString(Isolate* isolate, Local<String> v8_str) {
643 2298 : String::Utf8Value utf8(isolate, v8_str);
644 : // Should not be able to fail since the input is a String.
645 2298 : CHECK(*utf8);
646 2298 : return *utf8;
647 : }
648 :
649 : bool IsAbsolutePath(const std::string& path) {
650 : #if defined(_WIN32) || defined(_WIN64)
651 : // TODO(adamk): This is an incorrect approximation, but should
652 : // work for all our test-running cases.
653 : return path.find(':') != std::string::npos;
654 : #else
655 2759 : return path[0] == '/';
656 : #endif
657 : }
658 :
659 461 : std::string GetWorkingDirectory() {
660 : #if defined(_WIN32) || defined(_WIN64)
661 : char system_buffer[MAX_PATH];
662 : // TODO(adamk): Support Unicode paths.
663 : DWORD len = GetCurrentDirectoryA(MAX_PATH, system_buffer);
664 : CHECK_GT(len, 0);
665 : return system_buffer;
666 : #else
667 : char curdir[PATH_MAX];
668 461 : CHECK_NOT_NULL(getcwd(curdir, PATH_MAX));
669 461 : return curdir;
670 : #endif
671 : }
672 :
673 : // Returns the directory part of path, without the trailing '/'.
674 2303 : std::string DirName(const std::string& path) {
675 : DCHECK(IsAbsolutePath(path));
676 : size_t last_slash = path.find_last_of('/');
677 : DCHECK(last_slash != std::string::npos);
678 2303 : return path.substr(0, last_slash);
679 : }
680 :
681 : // Resolves path to an absolute path if necessary, and does some
682 : // normalization (eliding references to the current directory
683 : // and replacing backslashes with slashes).
684 2413 : std::string NormalizePath(const std::string& path,
685 : const std::string& dir_name) {
686 : std::string result;
687 2413 : if (IsAbsolutePath(path)) {
688 : result = path;
689 : } else {
690 3904 : result = dir_name + '/' + path;
691 : }
692 2413 : std::replace(result.begin(), result.end(), '\\', '/');
693 : size_t i;
694 2615 : while ((i = result.find("/./")) != std::string::npos) {
695 202 : result.erase(i, 2);
696 : }
697 2413 : return result;
698 : }
699 :
700 : // Per-context Module data, allowing sharing of module maps
701 : // across top-level module loads.
702 91052 : class ModuleEmbedderData {
703 : private:
704 : class ModuleGlobalHash {
705 : public:
706 45526 : explicit ModuleGlobalHash(Isolate* isolate) : isolate_(isolate) {}
707 1975 : size_t operator()(const Global<Module>& module) const {
708 3950 : return module.Get(isolate_)->GetIdentityHash();
709 : }
710 :
711 : private:
712 : Isolate* isolate_;
713 : };
714 :
715 : public:
716 45526 : explicit ModuleEmbedderData(Isolate* isolate)
717 91052 : : module_to_specifier_map(10, ModuleGlobalHash(isolate)) {}
718 :
719 : // Map from normalized module specifier to Module.
720 : std::unordered_map<std::string, Global<Module>> specifier_to_module_map;
721 : // Map from Module to its URL as defined in the ScriptOrigin
722 : std::unordered_map<Global<Module>, std::string, ModuleGlobalHash>
723 : module_to_specifier_map;
724 : };
725 :
726 : enum {
727 : kModuleEmbedderDataIndex,
728 : kInspectorClientIndex
729 : };
730 :
731 45526 : void InitializeModuleEmbedderData(Local<Context> context) {
732 : context->SetAlignedPointerInEmbedderData(
733 45526 : kModuleEmbedderDataIndex, new ModuleEmbedderData(context->GetIsolate()));
734 45526 : }
735 :
736 : ModuleEmbedderData* GetModuleDataFromContext(Local<Context> context) {
737 : return static_cast<ModuleEmbedderData*>(
738 : context->GetAlignedPointerFromEmbedderData(kModuleEmbedderDataIndex));
739 : }
740 :
741 45526 : void DisposeModuleEmbedderData(Local<Context> context) {
742 45526 : delete GetModuleDataFromContext(context);
743 45526 : context->SetAlignedPointerInEmbedderData(kModuleEmbedderDataIndex, nullptr);
744 45526 : }
745 :
746 803 : MaybeLocal<Module> ResolveModuleCallback(Local<Context> context,
747 : Local<String> specifier,
748 : Local<Module> referrer) {
749 803 : Isolate* isolate = context->GetIsolate();
750 : ModuleEmbedderData* d = GetModuleDataFromContext(context);
751 : auto specifier_it =
752 803 : d->module_to_specifier_map.find(Global<Module>(isolate, referrer));
753 803 : CHECK(specifier_it != d->module_to_specifier_map.end());
754 : std::string absolute_path = NormalizePath(ToSTLString(isolate, specifier),
755 2409 : DirName(specifier_it->second));
756 : auto module_it = d->specifier_to_module_map.find(absolute_path);
757 803 : CHECK(module_it != d->specifier_to_module_map.end());
758 1606 : return module_it->second.Get(isolate);
759 : }
760 :
761 : } // anonymous namespace
762 :
763 1248 : MaybeLocal<Module> Shell::FetchModuleTree(Local<Context> context,
764 : const std::string& file_name) {
765 : DCHECK(IsAbsolutePath(file_name));
766 1248 : Isolate* isolate = context->GetIsolate();
767 1248 : Local<String> source_text = ReadFile(isolate, file_name.c_str());
768 1248 : if (source_text.IsEmpty()) {
769 67 : std::string msg = "Error reading: " + file_name;
770 67 : Throw(isolate, msg.c_str());
771 67 : return MaybeLocal<Module>();
772 : }
773 : ScriptOrigin origin(
774 : String::NewFromUtf8(isolate, file_name.c_str(), NewStringType::kNormal)
775 : .ToLocalChecked(),
776 : Local<Integer>(), Local<Integer>(), Local<Boolean>(), Local<Integer>(),
777 1181 : Local<Value>(), Local<Boolean>(), Local<Boolean>(), True(isolate));
778 : ScriptCompiler::Source source(source_text, origin);
779 : Local<Module> module;
780 2362 : if (!ScriptCompiler::CompileModule(isolate, &source).ToLocal(&module)) {
781 27 : return MaybeLocal<Module>();
782 : }
783 :
784 : ModuleEmbedderData* d = GetModuleDataFromContext(context);
785 1154 : CHECK(d->specifier_to_module_map
786 : .insert(std::make_pair(file_name, Global<Module>(isolate, module)))
787 : .second);
788 1154 : CHECK(d->module_to_specifier_map
789 : .insert(std::make_pair(Global<Module>(isolate, module), file_name))
790 : .second);
791 :
792 1154 : std::string dir_name = DirName(file_name);
793 :
794 1957 : for (int i = 0, length = module->GetModuleRequestsLength(); i < length; ++i) {
795 803 : Local<String> name = module->GetModuleRequest(i);
796 : std::string absolute_path =
797 1606 : NormalizePath(ToSTLString(isolate, name), dir_name);
798 803 : if (!d->specifier_to_module_map.count(absolute_path)) {
799 1026 : if (FetchModuleTree(context, absolute_path).IsEmpty()) {
800 0 : return MaybeLocal<Module>();
801 : }
802 : }
803 : }
804 :
805 1154 : return module;
806 : }
807 :
808 : namespace {
809 :
810 692 : struct DynamicImportData {
811 346 : DynamicImportData(Isolate* isolate_, Local<String> referrer_,
812 : Local<String> specifier_,
813 : Local<Promise::Resolver> resolver_)
814 346 : : isolate(isolate_) {
815 : referrer.Reset(isolate, referrer_);
816 346 : specifier.Reset(isolate, specifier_);
817 346 : resolver.Reset(isolate, resolver_);
818 346 : }
819 :
820 : Isolate* isolate;
821 : Global<String> referrer;
822 : Global<String> specifier;
823 : Global<Promise::Resolver> resolver;
824 : };
825 :
826 : } // namespace
827 :
828 452 : MaybeLocal<Promise> Shell::HostImportModuleDynamically(
829 : Local<Context> context, Local<ScriptOrModule> referrer,
830 : Local<String> specifier) {
831 452 : Isolate* isolate = context->GetIsolate();
832 :
833 : MaybeLocal<Promise::Resolver> maybe_resolver =
834 452 : Promise::Resolver::New(context);
835 : Local<Promise::Resolver> resolver;
836 452 : if (maybe_resolver.ToLocal(&resolver)) {
837 : DynamicImportData* data = new DynamicImportData(
838 346 : isolate, Local<String>::Cast(referrer->GetResourceName()), specifier,
839 346 : resolver);
840 346 : isolate->EnqueueMicrotask(Shell::DoHostImportModuleDynamically, data);
841 346 : return resolver->GetPromise();
842 : }
843 :
844 106 : return MaybeLocal<Promise>();
845 : }
846 :
847 18 : void Shell::HostInitializeImportMetaObject(Local<Context> context,
848 : Local<Module> module,
849 : Local<Object> meta) {
850 18 : Isolate* isolate = context->GetIsolate();
851 18 : HandleScope handle_scope(isolate);
852 :
853 : ModuleEmbedderData* d = GetModuleDataFromContext(context);
854 : auto specifier_it =
855 18 : d->module_to_specifier_map.find(Global<Module>(isolate, module));
856 18 : CHECK(specifier_it != d->module_to_specifier_map.end());
857 :
858 : Local<String> url_key =
859 : String::NewFromUtf8(isolate, "url", NewStringType::kNormal)
860 18 : .ToLocalChecked();
861 : Local<String> url = String::NewFromUtf8(isolate, specifier_it->second.c_str(),
862 : NewStringType::kNormal)
863 18 : .ToLocalChecked();
864 36 : meta->CreateDataProperty(context, url_key, url).ToChecked();
865 18 : }
866 :
867 346 : void Shell::DoHostImportModuleDynamically(void* import_data) {
868 : std::unique_ptr<DynamicImportData> import_data_(
869 : static_cast<DynamicImportData*>(import_data));
870 346 : Isolate* isolate(import_data_->isolate);
871 535 : HandleScope handle_scope(isolate);
872 :
873 346 : Local<String> referrer(import_data_->referrer.Get(isolate));
874 346 : Local<String> specifier(import_data_->specifier.Get(isolate));
875 : Local<Promise::Resolver> resolver(import_data_->resolver.Get(isolate));
876 :
877 : PerIsolateData* data = PerIsolateData::Get(isolate);
878 346 : Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
879 : Context::Scope context_scope(realm);
880 :
881 346 : std::string source_url = ToSTLString(isolate, referrer);
882 : std::string dir_name =
883 : DirName(IsAbsolutePath(source_url)
884 : ? source_url
885 692 : : NormalizePath(source_url, GetWorkingDirectory()));
886 346 : std::string file_name = ToSTLString(isolate, specifier);
887 346 : std::string absolute_path = NormalizePath(file_name, dir_name);
888 :
889 535 : TryCatch try_catch(isolate);
890 346 : try_catch.SetVerbose(true);
891 :
892 : ModuleEmbedderData* d = GetModuleDataFromContext(realm);
893 : Local<Module> root_module;
894 : auto module_it = d->specifier_to_module_map.find(absolute_path);
895 346 : if (module_it != d->specifier_to_module_map.end()) {
896 : root_module = module_it->second.Get(isolate);
897 548 : } else if (!FetchModuleTree(realm, absolute_path).ToLocal(&root_module)) {
898 94 : CHECK(try_catch.HasCaught());
899 188 : resolver->Reject(realm, try_catch.Exception()).ToChecked();
900 251 : return;
901 : }
902 :
903 : MaybeLocal<Value> maybe_result;
904 252 : if (root_module->InstantiateModule(realm, ResolveModuleCallback)
905 504 : .FromMaybe(false)) {
906 216 : maybe_result = root_module->Evaluate(realm);
907 216 : EmptyMessageQueues(isolate);
908 : }
909 :
910 : Local<Value> module;
911 252 : if (!maybe_result.ToLocal(&module)) {
912 : DCHECK(try_catch.HasCaught());
913 126 : resolver->Reject(realm, try_catch.Exception()).ToChecked();
914 63 : return;
915 : }
916 :
917 : DCHECK(!try_catch.HasCaught());
918 189 : Local<Value> module_namespace = root_module->GetModuleNamespace();
919 378 : resolver->Resolve(realm, module_namespace).ToChecked();
920 : }
921 :
922 461 : bool Shell::ExecuteModule(Isolate* isolate, const char* file_name) {
923 461 : HandleScope handle_scope(isolate);
924 :
925 : PerIsolateData* data = PerIsolateData::Get(isolate);
926 461 : Local<Context> realm = data->realms_[data->realm_current_].Get(isolate);
927 : Context::Scope context_scope(realm);
928 :
929 1383 : std::string absolute_path = NormalizePath(file_name, GetWorkingDirectory());
930 :
931 922 : TryCatch try_catch(isolate);
932 461 : try_catch.SetVerbose(true);
933 :
934 : Local<Module> root_module;
935 : MaybeLocal<Value> maybe_exception;
936 :
937 922 : if (!FetchModuleTree(realm, absolute_path).ToLocal(&root_module)) {
938 0 : CHECK(try_catch.HasCaught());
939 0 : ReportException(isolate, &try_catch);
940 0 : return false;
941 : }
942 :
943 : MaybeLocal<Value> maybe_result;
944 461 : if (root_module->InstantiateModule(realm, ResolveModuleCallback)
945 922 : .FromMaybe(false)) {
946 461 : maybe_result = root_module->Evaluate(realm);
947 461 : EmptyMessageQueues(isolate);
948 : }
949 : Local<Value> result;
950 461 : if (!maybe_result.ToLocal(&result)) {
951 : DCHECK(try_catch.HasCaught());
952 : // Print errors that happened during execution.
953 0 : ReportException(isolate, &try_catch);
954 0 : return false;
955 : }
956 : DCHECK(!try_catch.HasCaught());
957 461 : return true;
958 : }
959 :
960 44874 : PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
961 44874 : data_->realm_count_ = 1;
962 44874 : data_->realm_current_ = 0;
963 44874 : data_->realm_switch_ = 0;
964 89748 : data_->realms_ = new Global<Context>[1];
965 44874 : data_->realms_[0].Reset(data_->isolate_,
966 89748 : data_->isolate_->GetEnteredContext());
967 44874 : }
968 :
969 :
970 44874 : PerIsolateData::RealmScope::~RealmScope() {
971 : // Drop realms to avoid keeping them alive. We don't dispose the
972 : // module embedder data for the first realm here, but instead do
973 : // it in RunShell or in RunMain, if not running in interactive mode
974 45536 : for (int i = 1; i < data_->realm_count_; ++i) {
975 662 : Global<Context>& realm = data_->realms_[i];
976 662 : if (realm.IsEmpty()) continue;
977 644 : DisposeModuleEmbedderData(realm.Get(data_->isolate_));
978 : // TODO(adamk): No need to reset manually, Globals reset when destructed.
979 : realm.Reset();
980 : }
981 44874 : data_->realm_count_ = 0;
982 89748 : delete[] data_->realms_;
983 : // TODO(adamk): No need to reset manually, Globals reset when destructed.
984 89748 : if (!data_->realm_shared_.IsEmpty())
985 : data_->realm_shared_.Reset();
986 44874 : }
987 :
988 :
989 332 : int PerIsolateData::RealmFind(Local<Context> context) {
990 2452 : for (int i = 0; i < realm_count_; ++i) {
991 4904 : if (realms_[i] == context) return i;
992 : }
993 : return -1;
994 : }
995 :
996 :
997 10324 : int PerIsolateData::RealmIndexOrThrow(
998 20658 : const v8::FunctionCallbackInfo<v8::Value>& args,
999 : int arg_offset) {
1000 20648 : if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
1001 0 : Throw(args.GetIsolate(), "Invalid argument");
1002 0 : return -1;
1003 : }
1004 : int index = args[arg_offset]
1005 10324 : ->Int32Value(args.GetIsolate()->GetCurrentContext())
1006 20648 : .FromMaybe(-1);
1007 20638 : if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
1008 10 : Throw(args.GetIsolate(), "Invalid realm index");
1009 10 : return -1;
1010 : }
1011 : return index;
1012 : }
1013 :
1014 :
1015 : // performance.now() returns a time stamp as double, measured in milliseconds.
1016 : // When FLAG_verify_predictable mode is enabled it returns result of
1017 : // v8::Platform::MonotonicallyIncreasingTime().
1018 6 : void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
1019 : if (i::FLAG_verify_predictable) {
1020 : args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
1021 : } else {
1022 : base::TimeDelta delta =
1023 6 : base::TimeTicks::HighResolutionNow() - kInitialTicks;
1024 3 : args.GetReturnValue().Set(delta.InMillisecondsF());
1025 : }
1026 3 : }
1027 :
1028 :
1029 : // Realm.current() returns the index of the currently active realm.
1030 664 : void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
1031 : Isolate* isolate = args.GetIsolate();
1032 : PerIsolateData* data = PerIsolateData::Get(isolate);
1033 332 : int index = data->RealmFind(isolate->GetEnteredContext());
1034 664 : if (index == -1) return;
1035 : args.GetReturnValue().Set(index);
1036 : }
1037 :
1038 :
1039 : // Realm.owner(o) returns the index of the realm that created o.
1040 0 : void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
1041 : Isolate* isolate = args.GetIsolate();
1042 : PerIsolateData* data = PerIsolateData::Get(isolate);
1043 0 : if (args.Length() < 1 || !args[0]->IsObject()) {
1044 0 : Throw(args.GetIsolate(), "Invalid argument");
1045 0 : return;
1046 : }
1047 : int index = data->RealmFind(args[0]
1048 0 : ->ToObject(isolate->GetCurrentContext())
1049 0 : .ToLocalChecked()
1050 0 : ->CreationContext());
1051 0 : if (index == -1) return;
1052 : args.GetReturnValue().Set(index);
1053 : }
1054 :
1055 :
1056 : // Realm.global(i) returns the global object of realm i.
1057 : // (Note that properties of global objects cannot be read/written cross-realm.)
1058 1422 : void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
1059 : PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
1060 474 : int index = data->RealmIndexOrThrow(args, 0);
1061 948 : if (index == -1) return;
1062 : args.GetReturnValue().Set(
1063 948 : Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
1064 : }
1065 :
1066 672 : MaybeLocal<Context> Shell::CreateRealm(
1067 1324 : const v8::FunctionCallbackInfo<v8::Value>& args, int index,
1068 : v8::MaybeLocal<Value> global_object) {
1069 : Isolate* isolate = args.GetIsolate();
1070 672 : TryCatch try_catch(isolate);
1071 : PerIsolateData* data = PerIsolateData::Get(isolate);
1072 672 : if (index < 0) {
1073 662 : Global<Context>* old_realms = data->realms_;
1074 662 : index = data->realm_count_;
1075 4683 : data->realms_ = new Global<Context>[++data->realm_count_];
1076 4021 : for (int i = 0; i < index; ++i) {
1077 3359 : data->realms_[i].Reset(isolate, old_realms[i]);
1078 : old_realms[i].Reset();
1079 : }
1080 1324 : delete[] old_realms;
1081 : }
1082 672 : Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
1083 : Local<Context> context =
1084 672 : Context::New(isolate, nullptr, global_template, global_object);
1085 : DCHECK(!try_catch.HasCaught());
1086 672 : if (context.IsEmpty()) return MaybeLocal<Context>();
1087 652 : InitializeModuleEmbedderData(context);
1088 652 : data->realms_[index].Reset(isolate, context);
1089 : args.GetReturnValue().Set(index);
1090 652 : return context;
1091 : }
1092 :
1093 330 : void Shell::DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
1094 : int index) {
1095 : Isolate* isolate = args.GetIsolate();
1096 : PerIsolateData* data = PerIsolateData::Get(isolate);
1097 660 : DisposeModuleEmbedderData(data->realms_[index].Get(isolate));
1098 330 : data->realms_[index].Reset();
1099 330 : isolate->ContextDisposedNotification();
1100 330 : isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
1101 330 : }
1102 :
1103 : // Realm.create() creates a new realm with a distinct security token
1104 : // and returns its index.
1105 652 : void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
1106 652 : CreateRealm(args, -1, v8::MaybeLocal<Value>());
1107 652 : }
1108 :
1109 : // Realm.createAllowCrossRealmAccess() creates a new realm with the same
1110 : // security token as the current realm.
1111 10 : void Shell::RealmCreateAllowCrossRealmAccess(
1112 10 : const v8::FunctionCallbackInfo<v8::Value>& args) {
1113 : Local<Context> context;
1114 20 : if (CreateRealm(args, -1, v8::MaybeLocal<Value>()).ToLocal(&context)) {
1115 : context->SetSecurityToken(
1116 20 : args.GetIsolate()->GetEnteredContext()->GetSecurityToken());
1117 : }
1118 10 : }
1119 :
1120 : // Realm.navigate(i) creates a new realm with a distinct security token
1121 : // in place of realm i.
1122 30 : void Shell::RealmNavigate(const v8::FunctionCallbackInfo<v8::Value>& args) {
1123 : Isolate* isolate = args.GetIsolate();
1124 : PerIsolateData* data = PerIsolateData::Get(isolate);
1125 20 : int index = data->RealmIndexOrThrow(args, 0);
1126 30 : if (index == -1) return;
1127 30 : if (index == 0 || index == data->realm_current_ ||
1128 10 : index == data->realm_switch_) {
1129 10 : Throw(args.GetIsolate(), "Invalid realm index");
1130 10 : return;
1131 : }
1132 :
1133 10 : Local<Context> context = Local<Context>::New(isolate, data->realms_[index]);
1134 10 : v8::MaybeLocal<Value> global_object = context->Global();
1135 10 : DisposeRealm(args, index);
1136 10 : CreateRealm(args, index, global_object);
1137 : }
1138 :
1139 : // Realm.dispose(i) disposes the reference to the realm i.
1140 320 : void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
1141 : Isolate* isolate = args.GetIsolate();
1142 : PerIsolateData* data = PerIsolateData::Get(isolate);
1143 320 : int index = data->RealmIndexOrThrow(args, 0);
1144 320 : if (index == -1) return;
1145 640 : if (index == 0 ||
1146 640 : index == data->realm_current_ || index == data->realm_switch_) {
1147 0 : Throw(args.GetIsolate(), "Invalid realm index");
1148 0 : return;
1149 : }
1150 320 : DisposeRealm(args, index);
1151 : }
1152 :
1153 :
1154 : // Realm.switch(i) switches to the realm i for consecutive interactive inputs.
1155 0 : void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
1156 : Isolate* isolate = args.GetIsolate();
1157 : PerIsolateData* data = PerIsolateData::Get(isolate);
1158 0 : int index = data->RealmIndexOrThrow(args, 0);
1159 0 : if (index == -1) return;
1160 0 : data->realm_switch_ = index;
1161 : }
1162 :
1163 :
1164 : // Realm.eval(i, s) evaluates s in realm i and returns the result.
1165 28084 : void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
1166 : Isolate* isolate = args.GetIsolate();
1167 : PerIsolateData* data = PerIsolateData::Get(isolate);
1168 9510 : int index = data->RealmIndexOrThrow(args, 0);
1169 9946 : if (index == -1) return;
1170 19000 : if (args.Length() < 2 || !args[1]->IsString()) {
1171 0 : Throw(args.GetIsolate(), "Invalid argument");
1172 0 : return;
1173 : }
1174 : ScriptCompiler::Source script_source(
1175 19000 : args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
1176 : Local<UnboundScript> script;
1177 9500 : if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
1178 9500 : .ToLocal(&script)) {
1179 : return;
1180 : }
1181 9490 : Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
1182 9490 : realm->Enter();
1183 9490 : int previous_index = data->realm_current_;
1184 9490 : data->realm_current_ = data->realm_switch_ = index;
1185 : Local<Value> result;
1186 28470 : if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
1187 416 : realm->Exit();
1188 416 : data->realm_current_ = data->realm_switch_ = previous_index;
1189 416 : return;
1190 : }
1191 9074 : realm->Exit();
1192 9074 : data->realm_current_ = data->realm_switch_ = previous_index;
1193 : args.GetReturnValue().Set(result);
1194 : }
1195 :
1196 :
1197 : // Realm.shared is an accessor for a single shared value across realms.
1198 5712 : void Shell::RealmSharedGet(Local<String> property,
1199 : const PropertyCallbackInfo<Value>& info) {
1200 : Isolate* isolate = info.GetIsolate();
1201 : PerIsolateData* data = PerIsolateData::Get(isolate);
1202 11424 : if (data->realm_shared_.IsEmpty()) return;
1203 : info.GetReturnValue().Set(data->realm_shared_);
1204 : }
1205 :
1206 277 : void Shell::RealmSharedSet(Local<String> property,
1207 : Local<Value> value,
1208 : const PropertyCallbackInfo<void>& info) {
1209 : Isolate* isolate = info.GetIsolate();
1210 : PerIsolateData* data = PerIsolateData::Get(isolate);
1211 : data->realm_shared_.Reset(isolate, value);
1212 277 : }
1213 :
1214 13767647 : void WriteToFile(FILE* file, const v8::FunctionCallbackInfo<v8::Value>& args) {
1215 6989084 : for (int i = 0; i < args.Length(); i++) {
1216 2259521 : HandleScope handle_scope(args.GetIsolate());
1217 2259521 : if (i != 0) {
1218 : fprintf(file, " ");
1219 : }
1220 :
1221 : // Explicitly catch potential exceptions in toString().
1222 4519042 : v8::TryCatch try_catch(args.GetIsolate());
1223 : Local<Value> arg = args[i];
1224 : Local<String> str_obj;
1225 :
1226 2259521 : if (arg->IsSymbol()) {
1227 0 : arg = Local<Symbol>::Cast(arg)->Name();
1228 : }
1229 4519042 : if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
1230 2259521 : .ToLocal(&str_obj)) {
1231 0 : try_catch.ReThrow();
1232 1235021 : return;
1233 : }
1234 :
1235 4519042 : v8::String::Utf8Value str(args.GetIsolate(), str_obj);
1236 2259521 : int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), file));
1237 2259521 : if (n != str.length()) {
1238 : printf("Error in fwrite\n");
1239 0 : Shell::Exit(1);
1240 : }
1241 2259521 : }
1242 : }
1243 :
1244 1235021 : void WriteAndFlush(FILE* file,
1245 : const v8::FunctionCallbackInfo<v8::Value>& args) {
1246 1235021 : WriteToFile(file, args);
1247 : fprintf(file, "\n");
1248 1235021 : fflush(file);
1249 1235021 : }
1250 :
1251 1235021 : void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
1252 1235021 : WriteAndFlush(stdout, args);
1253 1235021 : }
1254 :
1255 0 : void Shell::PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args) {
1256 0 : WriteAndFlush(stderr, args);
1257 0 : }
1258 :
1259 0 : void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
1260 0 : WriteToFile(stdout, args);
1261 0 : }
1262 :
1263 150 : void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
1264 30 : String::Utf8Value file(args.GetIsolate(), args[0]);
1265 30 : if (*file == nullptr) {
1266 0 : Throw(args.GetIsolate(), "Error loading file");
1267 0 : return;
1268 : }
1269 30 : if (args.Length() == 2) {
1270 0 : String::Utf8Value format(args.GetIsolate(), args[1]);
1271 0 : if (*format && std::strcmp(*format, "binary") == 0) {
1272 0 : ReadBuffer(args);
1273 0 : return;
1274 0 : }
1275 : }
1276 60 : Local<String> source = ReadFile(args.GetIsolate(), *file);
1277 30 : if (source.IsEmpty()) {
1278 0 : Throw(args.GetIsolate(), "Error loading file");
1279 0 : return;
1280 : }
1281 30 : args.GetReturnValue().Set(source);
1282 : }
1283 :
1284 :
1285 0 : Local<String> Shell::ReadFromStdin(Isolate* isolate) {
1286 : static const int kBufferSize = 256;
1287 : char buffer[kBufferSize];
1288 : Local<String> accumulator =
1289 0 : String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
1290 : int length;
1291 : while (true) {
1292 : // Continue reading if the line ends with an escape '\\' or the line has
1293 : // not been fully read into the buffer yet (does not end with '\n').
1294 : // If fgets gets an error, just give up.
1295 : char* input = nullptr;
1296 0 : input = fgets(buffer, kBufferSize, stdin);
1297 0 : if (input == nullptr) return Local<String>();
1298 0 : length = static_cast<int>(strlen(buffer));
1299 0 : if (length == 0) {
1300 0 : return accumulator;
1301 0 : } else if (buffer[length-1] != '\n') {
1302 : accumulator = String::Concat(
1303 : accumulator,
1304 : String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
1305 0 : .ToLocalChecked());
1306 0 : } else if (length > 1 && buffer[length-2] == '\\') {
1307 0 : buffer[length-2] = '\n';
1308 : accumulator = String::Concat(
1309 : accumulator,
1310 : String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
1311 0 : length - 1).ToLocalChecked());
1312 : } else {
1313 : return String::Concat(
1314 : accumulator,
1315 : String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
1316 0 : length - 1).ToLocalChecked());
1317 : }
1318 : }
1319 : }
1320 :
1321 :
1322 69866 : void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
1323 22398 : for (int i = 0; i < args.Length(); i++) {
1324 8737 : HandleScope handle_scope(args.GetIsolate());
1325 11199 : String::Utf8Value file(args.GetIsolate(), args[i]);
1326 8737 : if (*file == nullptr) {
1327 0 : Throw(args.GetIsolate(), "Error loading file");
1328 0 : return;
1329 : }
1330 8737 : Local<String> source = ReadFile(args.GetIsolate(), *file);
1331 8737 : if (source.IsEmpty()) {
1332 15 : Throw(args.GetIsolate(), "Error loading file");
1333 15 : return;
1334 : }
1335 8722 : if (!ExecuteString(
1336 : args.GetIsolate(), source,
1337 8722 : String::NewFromUtf8(args.GetIsolate(), *file,
1338 : NewStringType::kNormal).ToLocalChecked(),
1339 17444 : false, true)) {
1340 6260 : Throw(args.GetIsolate(), "Error executing file");
1341 6260 : return;
1342 : }
1343 2462 : }
1344 : }
1345 :
1346 180 : void Shell::SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) {
1347 : Isolate* isolate = args.GetIsolate();
1348 60 : args.GetReturnValue().Set(v8::Number::New(isolate, 0));
1349 120 : if (args.Length() == 0 || !args[0]->IsFunction()) return;
1350 60 : Local<Function> callback = Local<Function>::Cast(args[0]);
1351 60 : Local<Context> context = isolate->GetCurrentContext();
1352 60 : PerIsolateData::Get(isolate)->SetTimeout(callback, context);
1353 : }
1354 :
1355 2015 : void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
1356 : Isolate* isolate = args.GetIsolate();
1357 417 : HandleScope handle_scope(isolate);
1358 824 : if (args.Length() < 1 || !args[0]->IsString()) {
1359 10 : Throw(args.GetIsolate(), "1st argument must be string");
1360 40 : return;
1361 : }
1362 :
1363 407 : if (!args.IsConstructCall()) {
1364 10 : Throw(args.GetIsolate(), "Worker must be constructed with new");
1365 10 : return;
1366 : }
1367 :
1368 : {
1369 : base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
1370 794 : if (workers_.size() >= kMaxWorkers) {
1371 0 : Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
1372 0 : return;
1373 : }
1374 :
1375 : // Initialize the embedder field to nullptr; if we return early without
1376 : // creating a new Worker (because the main thread is terminating) we can
1377 : // early-out from the instance calls.
1378 397 : args.Holder()->SetAlignedPointerInInternalField(0, nullptr);
1379 :
1380 397 : if (!allow_new_workers_) return;
1381 :
1382 387 : Worker* worker = new Worker;
1383 387 : args.Holder()->SetAlignedPointerInInternalField(0, worker);
1384 387 : workers_.push_back(worker);
1385 :
1386 774 : String::Utf8Value script(args.GetIsolate(), args[0]);
1387 387 : if (!*script) {
1388 0 : Throw(args.GetIsolate(), "Can't get worker script");
1389 0 : return;
1390 : }
1391 387 : worker->StartExecuteInThread(*script);
1392 387 : }
1393 : }
1394 :
1395 :
1396 1779 : void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
1397 : Isolate* isolate = args.GetIsolate();
1398 593 : HandleScope handle_scope(isolate);
1399 :
1400 593 : if (args.Length() < 1) {
1401 0 : Throw(isolate, "Invalid argument");
1402 0 : return;
1403 : }
1404 :
1405 593 : Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
1406 593 : if (!worker) {
1407 : return;
1408 : }
1409 :
1410 583 : Local<Value> message = args[0];
1411 : Local<Value> transfer =
1412 1166 : args.Length() >= 2 ? args[1] : Local<Value>::Cast(Undefined(isolate));
1413 : std::unique_ptr<SerializationData> data =
1414 583 : Shell::SerializeValue(isolate, message, transfer);
1415 583 : if (data) {
1416 814 : worker->PostMessage(std::move(data));
1417 583 : }
1418 : }
1419 :
1420 :
1421 951 : void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
1422 : Isolate* isolate = args.GetIsolate();
1423 327 : HandleScope handle_scope(isolate);
1424 327 : Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
1425 327 : if (!worker) {
1426 0 : return;
1427 : }
1428 :
1429 327 : std::unique_ptr<SerializationData> data = worker->GetMessage();
1430 327 : if (data) {
1431 : Local<Value> value;
1432 594 : if (Shell::DeserializeValue(isolate, std::move(data)).ToLocal(&value)) {
1433 : args.GetReturnValue().Set(value);
1434 : }
1435 327 : }
1436 : }
1437 :
1438 :
1439 434 : void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
1440 : Isolate* isolate = args.GetIsolate();
1441 217 : HandleScope handle_scope(isolate);
1442 217 : Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
1443 217 : if (!worker) {
1444 0 : return;
1445 : }
1446 :
1447 217 : worker->Terminate();
1448 : }
1449 :
1450 :
1451 0 : void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
1452 : int exit_code = (*args)[0]
1453 0 : ->Int32Value(args->GetIsolate()->GetCurrentContext())
1454 0 : .FromMaybe(0);
1455 0 : CleanupWorkers();
1456 0 : args->GetIsolate()->Exit();
1457 0 : OnExit(args->GetIsolate());
1458 0 : Exit(exit_code);
1459 0 : }
1460 :
1461 :
1462 0 : void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
1463 : base::CallOnce(&quit_once_, &QuitOnce,
1464 0 : const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
1465 0 : }
1466 :
1467 920 : void Shell::WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
1468 920 : SetWaitUntilDone(args.GetIsolate(), true);
1469 920 : }
1470 :
1471 150 : void Shell::NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args) {
1472 150 : SetWaitUntilDone(args.GetIsolate(), false);
1473 150 : }
1474 :
1475 90 : void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
1476 : args.GetReturnValue().Set(
1477 : String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
1478 60 : NewStringType::kNormal).ToLocalChecked());
1479 30 : }
1480 :
1481 :
1482 7637 : void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
1483 7637 : HandleScope handle_scope(isolate);
1484 7637 : Local<Context> context = isolate->GetCurrentContext();
1485 : bool enter_context = context.IsEmpty();
1486 7637 : if (enter_context) {
1487 : context = Local<Context>::New(isolate, evaluation_context_);
1488 0 : context->Enter();
1489 : }
1490 : // Converts a V8 value to a C string.
1491 24278 : auto ToCString = [](const v8::String::Utf8Value& value) {
1492 : return *value ? *value : "<string conversion failed>";
1493 24278 : };
1494 :
1495 15274 : v8::String::Utf8Value exception(isolate, try_catch->Exception());
1496 : const char* exception_string = ToCString(exception);
1497 7637 : Local<Message> message = try_catch->Message();
1498 7637 : if (message.IsEmpty()) {
1499 : // V8 didn't provide any extra information about this error; just
1500 : // print the exception.
1501 : printf("%s\n", exception_string);
1502 15274 : } else if (message->GetScriptOrigin().Options().IsWasm()) {
1503 : // Print wasm-function[(function index)]:(offset): (message).
1504 0 : int function_index = message->GetLineNumber(context).FromJust() - 1;
1505 0 : int offset = message->GetStartColumn(context).FromJust();
1506 : printf("wasm-function[%d]:%d: %s\n", function_index, offset,
1507 : exception_string);
1508 : } else {
1509 : // Print (filename):(line number): (message).
1510 : v8::String::Utf8Value filename(isolate,
1511 7637 : message->GetScriptOrigin().ResourceName());
1512 : const char* filename_string = ToCString(filename);
1513 15274 : int linenum = message->GetLineNumber(context).FromMaybe(-1);
1514 : printf("%s:%i: %s\n", filename_string, linenum, exception_string);
1515 : Local<String> sourceline;
1516 15274 : if (message->GetSourceLine(context).ToLocal(&sourceline)) {
1517 : // Print line of source code.
1518 7637 : v8::String::Utf8Value sourcelinevalue(isolate, sourceline);
1519 : const char* sourceline_string = ToCString(sourcelinevalue);
1520 : printf("%s\n", sourceline_string);
1521 : // Print wavy underline (GetUnderline is deprecated).
1522 15274 : int start = message->GetStartColumn(context).FromJust();
1523 65671 : for (int i = 0; i < start; i++) {
1524 : printf(" ");
1525 : }
1526 15274 : int end = message->GetEndColumn(context).FromJust();
1527 22187 : for (int i = start; i < end; i++) {
1528 : printf("^");
1529 : }
1530 7637 : printf("\n");
1531 7637 : }
1532 : }
1533 : Local<Value> stack_trace_string;
1534 16651 : if (try_catch->StackTrace(context).ToLocal(&stack_trace_string) &&
1535 : stack_trace_string->IsString()) {
1536 : v8::String::Utf8Value stack_trace(isolate,
1537 1367 : Local<String>::Cast(stack_trace_string));
1538 1367 : printf("%s\n", ToCString(stack_trace));
1539 : }
1540 : printf("\n");
1541 15274 : if (enter_context) context->Exit();
1542 7637 : }
1543 :
1544 :
1545 0 : int32_t* Counter::Bind(const char* name, bool is_histogram) {
1546 : int i;
1547 0 : for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
1548 0 : name_[i] = static_cast<char>(name[i]);
1549 0 : name_[i] = '\0';
1550 0 : is_histogram_ = is_histogram;
1551 0 : return ptr();
1552 : }
1553 :
1554 :
1555 0 : void Counter::AddSample(int32_t sample) {
1556 0 : count_++;
1557 0 : sample_total_ += sample;
1558 0 : }
1559 :
1560 :
1561 0 : CounterCollection::CounterCollection() {
1562 26783 : magic_number_ = 0xDEADFACE;
1563 26783 : max_counters_ = kMaxCounters;
1564 26783 : max_name_size_ = Counter::kMaxNameSize;
1565 26783 : counters_in_use_ = 0;
1566 0 : }
1567 :
1568 :
1569 0 : Counter* CounterCollection::GetNextCounter() {
1570 0 : if (counters_in_use_ == kMaxCounters) return nullptr;
1571 0 : return &counters_[counters_in_use_++];
1572 : }
1573 :
1574 :
1575 0 : void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
1576 : counters_file_ = base::OS::MemoryMappedFile::create(
1577 0 : name, sizeof(CounterCollection), &local_counters_);
1578 : void* memory =
1579 0 : (counters_file_ == nullptr) ? nullptr : counters_file_->memory();
1580 0 : if (memory == nullptr) {
1581 : printf("Could not map counters file %s\n", name);
1582 0 : Exit(1);
1583 : }
1584 0 : counters_ = static_cast<CounterCollection*>(memory);
1585 0 : isolate->SetCounterFunction(LookupCounter);
1586 0 : isolate->SetCreateHistogramFunction(CreateHistogram);
1587 0 : isolate->SetAddHistogramSampleFunction(AddHistogramSample);
1588 0 : }
1589 :
1590 :
1591 0 : int CounterMap::Hash(const char* name) {
1592 : int h = 0;
1593 : int c;
1594 0 : while ((c = *name++) != 0) {
1595 0 : h += h << 5;
1596 0 : h += c;
1597 : }
1598 0 : return h;
1599 : }
1600 :
1601 :
1602 0 : Counter* Shell::GetCounter(const char* name, bool is_histogram) {
1603 0 : Counter* counter = counter_map_->Lookup(name);
1604 :
1605 0 : if (counter == nullptr) {
1606 0 : counter = counters_->GetNextCounter();
1607 0 : if (counter != nullptr) {
1608 0 : counter_map_->Set(name, counter);
1609 : counter->Bind(name, is_histogram);
1610 : }
1611 : } else {
1612 : DCHECK(counter->is_histogram() == is_histogram);
1613 : }
1614 0 : return counter;
1615 : }
1616 :
1617 :
1618 0 : int* Shell::LookupCounter(const char* name) {
1619 0 : Counter* counter = GetCounter(name, false);
1620 :
1621 0 : if (counter != nullptr) {
1622 0 : return counter->ptr();
1623 : } else {
1624 : return nullptr;
1625 : }
1626 : }
1627 :
1628 :
1629 0 : void* Shell::CreateHistogram(const char* name,
1630 : int min,
1631 : int max,
1632 : size_t buckets) {
1633 0 : return GetCounter(name, true);
1634 : }
1635 :
1636 :
1637 0 : void Shell::AddHistogramSample(void* histogram, int sample) {
1638 : Counter* counter = reinterpret_cast<Counter*>(histogram);
1639 : counter->AddSample(sample);
1640 0 : }
1641 :
1642 : // Turn a value into a human-readable string.
1643 0 : Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
1644 : v8::Local<v8::Context> context =
1645 0 : v8::Local<v8::Context>::New(isolate, evaluation_context_);
1646 0 : if (stringify_function_.IsEmpty()) {
1647 0 : int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
1648 : i::Vector<const char> source_string =
1649 0 : i::NativesCollection<i::D8>::GetScriptSource(source_index);
1650 : i::Vector<const char> source_name =
1651 0 : i::NativesCollection<i::D8>::GetScriptName(source_index);
1652 : Local<String> source =
1653 : String::NewFromUtf8(isolate, source_string.start(),
1654 0 : NewStringType::kNormal, source_string.length())
1655 0 : .ToLocalChecked();
1656 : Local<String> name =
1657 : String::NewFromUtf8(isolate, source_name.start(),
1658 0 : NewStringType::kNormal, source_name.length())
1659 0 : .ToLocalChecked();
1660 : ScriptOrigin origin(name);
1661 : Local<Script> script =
1662 0 : Script::Compile(context, source, &origin).ToLocalChecked();
1663 : stringify_function_.Reset(
1664 0 : isolate, script->Run(context).ToLocalChecked().As<Function>());
1665 : }
1666 : Local<Function> fun = Local<Function>::New(isolate, stringify_function_);
1667 0 : Local<Value> argv[1] = {value};
1668 0 : v8::TryCatch try_catch(isolate);
1669 0 : MaybeLocal<Value> result = fun->Call(context, Undefined(isolate), 1, argv);
1670 0 : if (result.IsEmpty()) return String::Empty(isolate);
1671 0 : return result.ToLocalChecked().As<String>();
1672 : }
1673 :
1674 :
1675 45546 : Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
1676 45546 : Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
1677 : global_template->Set(
1678 : String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
1679 : .ToLocalChecked(),
1680 136638 : FunctionTemplate::New(isolate, Print));
1681 : global_template->Set(
1682 : String::NewFromUtf8(isolate, "printErr", NewStringType::kNormal)
1683 : .ToLocalChecked(),
1684 136638 : FunctionTemplate::New(isolate, PrintErr));
1685 : global_template->Set(
1686 : String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
1687 : .ToLocalChecked(),
1688 136638 : FunctionTemplate::New(isolate, Write));
1689 : global_template->Set(
1690 : String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
1691 : .ToLocalChecked(),
1692 136638 : FunctionTemplate::New(isolate, Read));
1693 : global_template->Set(
1694 : String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
1695 : .ToLocalChecked(),
1696 136638 : FunctionTemplate::New(isolate, ReadBuffer));
1697 : global_template->Set(
1698 : String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
1699 : .ToLocalChecked(),
1700 136638 : FunctionTemplate::New(isolate, ReadLine));
1701 : global_template->Set(
1702 : String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
1703 : .ToLocalChecked(),
1704 136638 : FunctionTemplate::New(isolate, Load));
1705 : global_template->Set(
1706 : String::NewFromUtf8(isolate, "setTimeout", NewStringType::kNormal)
1707 : .ToLocalChecked(),
1708 136638 : FunctionTemplate::New(isolate, SetTimeout));
1709 : // Some Emscripten-generated code tries to call 'quit', which in turn would
1710 : // call C's exit(). This would lead to memory leaks, because there is no way
1711 : // we can terminate cleanly then, so we need a way to hide 'quit'.
1712 45546 : if (!options.omit_quit) {
1713 : global_template->Set(
1714 : String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
1715 : .ToLocalChecked(),
1716 136551 : FunctionTemplate::New(isolate, Quit));
1717 : }
1718 45546 : Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
1719 : global_template->Set(
1720 : String::NewFromUtf8(isolate, "testRunner", NewStringType::kNormal)
1721 : .ToLocalChecked(),
1722 91092 : test_template);
1723 : test_template->Set(
1724 : String::NewFromUtf8(isolate, "notifyDone", NewStringType::kNormal)
1725 : .ToLocalChecked(),
1726 136638 : FunctionTemplate::New(isolate, NotifyDone));
1727 : test_template->Set(
1728 : String::NewFromUtf8(isolate, "waitUntilDone", NewStringType::kNormal)
1729 : .ToLocalChecked(),
1730 136638 : FunctionTemplate::New(isolate, WaitUntilDone));
1731 : global_template->Set(
1732 : String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
1733 : .ToLocalChecked(),
1734 136638 : FunctionTemplate::New(isolate, Version));
1735 : global_template->Set(
1736 : Symbol::GetToStringTag(isolate),
1737 : String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1738 136638 : .ToLocalChecked());
1739 :
1740 : // Bind the Realm object.
1741 45546 : Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
1742 : realm_template->Set(
1743 : String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
1744 : .ToLocalChecked(),
1745 136638 : FunctionTemplate::New(isolate, RealmCurrent));
1746 : realm_template->Set(
1747 : String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
1748 : .ToLocalChecked(),
1749 136638 : FunctionTemplate::New(isolate, RealmOwner));
1750 : realm_template->Set(
1751 : String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1752 : .ToLocalChecked(),
1753 136638 : FunctionTemplate::New(isolate, RealmGlobal));
1754 : realm_template->Set(
1755 : String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
1756 : .ToLocalChecked(),
1757 136638 : FunctionTemplate::New(isolate, RealmCreate));
1758 : realm_template->Set(
1759 : String::NewFromUtf8(isolate, "createAllowCrossRealmAccess",
1760 : NewStringType::kNormal)
1761 : .ToLocalChecked(),
1762 136638 : FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
1763 : realm_template->Set(
1764 : String::NewFromUtf8(isolate, "navigate", NewStringType::kNormal)
1765 : .ToLocalChecked(),
1766 136638 : FunctionTemplate::New(isolate, RealmNavigate));
1767 : realm_template->Set(
1768 : String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
1769 : .ToLocalChecked(),
1770 136638 : FunctionTemplate::New(isolate, RealmDispose));
1771 : realm_template->Set(
1772 : String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
1773 : .ToLocalChecked(),
1774 136638 : FunctionTemplate::New(isolate, RealmSwitch));
1775 : realm_template->Set(
1776 : String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
1777 : .ToLocalChecked(),
1778 136638 : FunctionTemplate::New(isolate, RealmEval));
1779 : realm_template->SetAccessor(
1780 : String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
1781 : .ToLocalChecked(),
1782 91092 : RealmSharedGet, RealmSharedSet);
1783 : global_template->Set(
1784 : String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
1785 : .ToLocalChecked(),
1786 91092 : realm_template);
1787 :
1788 45546 : Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
1789 : performance_template->Set(
1790 : String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
1791 : .ToLocalChecked(),
1792 136638 : FunctionTemplate::New(isolate, PerformanceNow));
1793 : global_template->Set(
1794 : String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
1795 : .ToLocalChecked(),
1796 91092 : performance_template);
1797 :
1798 : Local<FunctionTemplate> worker_fun_template =
1799 45546 : FunctionTemplate::New(isolate, WorkerNew);
1800 : Local<Signature> worker_signature =
1801 45546 : Signature::New(isolate, worker_fun_template);
1802 : worker_fun_template->SetClassName(
1803 : String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1804 91092 : .ToLocalChecked());
1805 45546 : worker_fun_template->ReadOnlyPrototype();
1806 91092 : worker_fun_template->PrototypeTemplate()->Set(
1807 : String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
1808 : .ToLocalChecked(),
1809 : FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
1810 182184 : worker_signature));
1811 91092 : worker_fun_template->PrototypeTemplate()->Set(
1812 : String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
1813 : .ToLocalChecked(),
1814 : FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
1815 182184 : worker_signature));
1816 91092 : worker_fun_template->PrototypeTemplate()->Set(
1817 : String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
1818 : .ToLocalChecked(),
1819 : FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
1820 182184 : worker_signature));
1821 91092 : worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
1822 : global_template->Set(
1823 : String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1824 : .ToLocalChecked(),
1825 91092 : worker_fun_template);
1826 :
1827 45546 : Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
1828 45546 : AddOSMethods(isolate, os_templ);
1829 : global_template->Set(
1830 : String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
1831 : .ToLocalChecked(),
1832 91092 : os_templ);
1833 :
1834 45546 : return global_template;
1835 : }
1836 :
1837 9368 : static void PrintNonErrorsMessageCallback(Local<Message> message,
1838 : Local<Value> error) {
1839 : // Nothing to do here for errors, exceptions thrown up to the shell will be
1840 : // reported
1841 : // separately by {Shell::ReportException} after they are caught.
1842 : // Do print other kinds of messages.
1843 9368 : switch (message->ErrorLevel()) {
1844 : case v8::Isolate::kMessageWarning:
1845 : case v8::Isolate::kMessageLog:
1846 : case v8::Isolate::kMessageInfo:
1847 : case v8::Isolate::kMessageDebug: {
1848 : break;
1849 : }
1850 :
1851 : case v8::Isolate::kMessageError: {
1852 : // Ignore errors, printed elsewhere.
1853 7789 : return;
1854 : }
1855 :
1856 : default: {
1857 0 : UNREACHABLE();
1858 : break;
1859 : }
1860 : }
1861 : // Converts a V8 value to a C string.
1862 3158 : auto ToCString = [](const v8::String::Utf8Value& value) {
1863 : return *value ? *value : "<string conversion failed>";
1864 3158 : };
1865 1579 : Isolate* isolate = Isolate::GetCurrent();
1866 3158 : v8::String::Utf8Value msg(isolate, message->Get());
1867 : const char* msg_string = ToCString(msg);
1868 : // Print (filename):(line number): (message).
1869 : v8::String::Utf8Value filename(isolate,
1870 3158 : message->GetScriptOrigin().ResourceName());
1871 : const char* filename_string = ToCString(filename);
1872 1579 : Maybe<int> maybeline = message->GetLineNumber(isolate->GetCurrentContext());
1873 1579 : int linenum = maybeline.IsJust() ? maybeline.FromJust() : -1;
1874 1579 : printf("%s:%i: %s\n", filename_string, linenum, msg_string);
1875 : }
1876 :
1877 26783 : void Shell::Initialize(Isolate* isolate) {
1878 : // Set up counters
1879 53566 : if (i::StrLength(i::FLAG_map_counters) != 0)
1880 0 : MapCounters(isolate, i::FLAG_map_counters);
1881 : // Disable default message reporting.
1882 : isolate->AddMessageListenerWithErrorLevel(
1883 : PrintNonErrorsMessageCallback,
1884 : v8::Isolate::kMessageError | v8::Isolate::kMessageWarning |
1885 : v8::Isolate::kMessageInfo | v8::Isolate::kMessageDebug |
1886 26783 : v8::Isolate::kMessageLog);
1887 26783 : }
1888 :
1889 :
1890 44874 : Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
1891 : // This needs to be a critical section since this is not thread-safe
1892 : base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
1893 : // Initialize the global objects
1894 44874 : Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
1895 44874 : EscapableHandleScope handle_scope(isolate);
1896 44874 : Local<Context> context = Context::New(isolate, nullptr, global_template);
1897 : DCHECK(!context.IsEmpty());
1898 44874 : InitializeModuleEmbedderData(context);
1899 : Context::Scope scope(context);
1900 :
1901 : i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
1902 44874 : i::JSArguments js_args = i::FLAG_js_arguments;
1903 : i::Handle<i::FixedArray> arguments_array =
1904 44874 : factory->NewFixedArray(js_args.argc);
1905 44874 : for (int j = 0; j < js_args.argc; j++) {
1906 : i::Handle<i::String> arg =
1907 0 : factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
1908 0 : arguments_array->set(j, *arg);
1909 : }
1910 : i::Handle<i::JSArray> arguments_jsarray =
1911 : factory->NewJSArrayWithElements(arguments_array);
1912 : context->Global()
1913 : ->Set(context,
1914 : String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
1915 : .ToLocalChecked(),
1916 134622 : Utils::ToLocal(arguments_jsarray))
1917 89748 : .FromJust();
1918 44874 : return handle_scope.Escape(context);
1919 : }
1920 :
1921 : struct CounterAndKey {
1922 : Counter* counter;
1923 : const char* key;
1924 : };
1925 :
1926 :
1927 : inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
1928 0 : return strcmp(lhs.key, rhs.key) < 0;
1929 : }
1930 :
1931 0 : void Shell::WriteIgnitionDispatchCountersFile(v8::Isolate* isolate) {
1932 0 : HandleScope handle_scope(isolate);
1933 0 : Local<Context> context = Context::New(isolate);
1934 : Context::Scope context_scope(context);
1935 :
1936 : Local<Object> dispatch_counters = reinterpret_cast<i::Isolate*>(isolate)
1937 : ->interpreter()
1938 0 : ->GetDispatchCountersObject();
1939 : std::ofstream dispatch_counters_stream(
1940 0 : i::FLAG_trace_ignition_dispatches_output_file);
1941 : dispatch_counters_stream << *String::Utf8Value(
1942 0 : isolate, JSON::Stringify(context, dispatch_counters).ToLocalChecked());
1943 0 : }
1944 :
1945 : namespace {
1946 0 : int LineFromOffset(Local<debug::Script> script, int offset) {
1947 0 : debug::Location location = script->GetSourceLocation(offset);
1948 0 : return location.GetLineNumber();
1949 : }
1950 :
1951 0 : void WriteLcovDataForRange(std::vector<uint32_t>& lines, int start_line,
1952 : int end_line, uint32_t count) {
1953 : // Ensure space in the array.
1954 0 : lines.resize(std::max(static_cast<size_t>(end_line + 1), lines.size()), 0);
1955 : // Boundary lines could be shared between two functions with different
1956 : // invocation counts. Take the maximum.
1957 0 : lines[start_line] = std::max(lines[start_line], count);
1958 0 : lines[end_line] = std::max(lines[end_line], count);
1959 : // Invocation counts for non-boundary lines are overwritten.
1960 0 : for (int k = start_line + 1; k < end_line; k++) lines[k] = count;
1961 0 : }
1962 :
1963 0 : void WriteLcovDataForNamedRange(std::ostream& sink,
1964 : std::vector<uint32_t>& lines, std::string name,
1965 : int start_line, int end_line, uint32_t count) {
1966 0 : WriteLcovDataForRange(lines, start_line, end_line, count);
1967 0 : sink << "FN:" << start_line + 1 << "," << name << std::endl;
1968 0 : sink << "FNDA:" << count << "," << name << std::endl;
1969 0 : }
1970 : } // namespace
1971 :
1972 : // Write coverage data in LCOV format. See man page for geninfo(1).
1973 44487 : void Shell::WriteLcovData(v8::Isolate* isolate, const char* file) {
1974 88974 : if (!file) return;
1975 0 : HandleScope handle_scope(isolate);
1976 0 : debug::Coverage coverage = debug::Coverage::CollectPrecise(isolate);
1977 0 : std::ofstream sink(file, std::ofstream::app);
1978 0 : for (size_t i = 0; i < coverage.ScriptCount(); i++) {
1979 0 : debug::Coverage::ScriptData script_data = coverage.GetScriptData(i);
1980 0 : Local<debug::Script> script = script_data.GetScript();
1981 : // Skip unnamed scripts.
1982 : Local<String> name;
1983 0 : if (!script->Name().ToLocal(&name)) continue;
1984 0 : std::string file_name = ToSTLString(isolate, name);
1985 : // Skip scripts not backed by a file.
1986 0 : if (!std::ifstream(file_name).good()) continue;
1987 0 : sink << "SF:";
1988 0 : sink << NormalizePath(file_name, GetWorkingDirectory()) << std::endl;
1989 : std::vector<uint32_t> lines;
1990 0 : for (size_t j = 0; j < script_data.FunctionCount(); j++) {
1991 : debug::Coverage::FunctionData function_data =
1992 0 : script_data.GetFunctionData(j);
1993 :
1994 : // Write function stats.
1995 : {
1996 : debug::Location start =
1997 0 : script->GetSourceLocation(function_data.StartOffset());
1998 : debug::Location end =
1999 0 : script->GetSourceLocation(function_data.EndOffset());
2000 0 : int start_line = start.GetLineNumber();
2001 0 : int end_line = end.GetLineNumber();
2002 0 : uint32_t count = function_data.Count();
2003 :
2004 : Local<String> name;
2005 0 : std::stringstream name_stream;
2006 0 : if (function_data.Name().ToLocal(&name)) {
2007 0 : name_stream << ToSTLString(isolate, name);
2008 : } else {
2009 0 : name_stream << "<" << start_line + 1 << "-";
2010 0 : name_stream << start.GetColumnNumber() << ">";
2011 : }
2012 :
2013 : WriteLcovDataForNamedRange(sink, lines, name_stream.str(), start_line,
2014 0 : end_line, count);
2015 : }
2016 :
2017 : // Process inner blocks.
2018 0 : for (size_t k = 0; k < function_data.BlockCount(); k++) {
2019 0 : debug::Coverage::BlockData block_data = function_data.GetBlockData(k);
2020 0 : int start_line = LineFromOffset(script, block_data.StartOffset());
2021 0 : int end_line = LineFromOffset(script, block_data.EndOffset() - 1);
2022 0 : uint32_t count = block_data.Count();
2023 0 : WriteLcovDataForRange(lines, start_line, end_line, count);
2024 : }
2025 : }
2026 : // Write per-line coverage. LCOV uses 1-based line numbers.
2027 0 : for (size_t i = 0; i < lines.size(); i++) {
2028 0 : sink << "DA:" << (i + 1) << "," << lines[i] << std::endl;
2029 : }
2030 0 : sink << "end_of_record" << std::endl;
2031 0 : }
2032 : }
2033 :
2034 26783 : void Shell::OnExit(v8::Isolate* isolate) {
2035 : // Dump basic block profiling data.
2036 26783 : if (i::BasicBlockProfiler* profiler =
2037 : reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
2038 0 : i::OFStream os(stdout);
2039 0 : os << *profiler;
2040 : }
2041 26783 : isolate->Dispose();
2042 :
2043 26783 : if (i::FLAG_dump_counters || i::FLAG_dump_counters_nvp) {
2044 : int number_of_counters = 0;
2045 0 : for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
2046 0 : number_of_counters++;
2047 : }
2048 0 : CounterAndKey* counters = new CounterAndKey[number_of_counters];
2049 : int j = 0;
2050 0 : for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
2051 0 : counters[j].counter = i.CurrentValue();
2052 0 : counters[j].key = i.CurrentKey();
2053 : }
2054 0 : std::sort(counters, counters + number_of_counters);
2055 :
2056 0 : if (i::FLAG_dump_counters_nvp) {
2057 : // Dump counters as name-value pairs.
2058 0 : for (j = 0; j < number_of_counters; j++) {
2059 0 : Counter* counter = counters[j].counter;
2060 0 : const char* key = counters[j].key;
2061 0 : if (counter->is_histogram()) {
2062 : printf("\"c:%s\"=%i\n", key, counter->count());
2063 : printf("\"t:%s\"=%i\n", key, counter->sample_total());
2064 : } else {
2065 : printf("\"%s\"=%i\n", key, counter->count());
2066 : }
2067 : }
2068 : } else {
2069 : // Dump counters in formatted boxes.
2070 : printf(
2071 : "+----------------------------------------------------------------+"
2072 : "-------------+\n");
2073 : printf(
2074 : "| Name |"
2075 : " Value |\n");
2076 : printf(
2077 : "+----------------------------------------------------------------+"
2078 : "-------------+\n");
2079 0 : for (j = 0; j < number_of_counters; j++) {
2080 0 : Counter* counter = counters[j].counter;
2081 0 : const char* key = counters[j].key;
2082 0 : if (counter->is_histogram()) {
2083 : printf("| c:%-60s | %11i |\n", key, counter->count());
2084 : printf("| t:%-60s | %11i |\n", key, counter->sample_total());
2085 : } else {
2086 : printf("| %-62s | %11i |\n", key, counter->count());
2087 : }
2088 : }
2089 : printf(
2090 : "+----------------------------------------------------------------+"
2091 : "-------------+\n");
2092 : }
2093 0 : delete [] counters;
2094 : }
2095 :
2096 26783 : delete counters_file_;
2097 53566 : delete counter_map_;
2098 26783 : }
2099 :
2100 :
2101 103792 : static FILE* FOpen(const char* path, const char* mode) {
2102 : #if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
2103 : FILE* result;
2104 : if (fopen_s(&result, path, mode) == 0) {
2105 : return result;
2106 : } else {
2107 : return nullptr;
2108 : }
2109 : #else
2110 103792 : FILE* file = fopen(path, mode);
2111 103792 : if (file == nullptr) return nullptr;
2112 : struct stat file_stat;
2113 207420 : if (fstat(fileno(file), &file_stat) != 0) return nullptr;
2114 103710 : bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
2115 103710 : if (is_regular_file) return file;
2116 0 : fclose(file);
2117 0 : return nullptr;
2118 : #endif
2119 : }
2120 :
2121 103792 : static char* ReadChars(const char* name, int* size_out) {
2122 103792 : if (Shell::options.read_from_tcp_port >= 0) {
2123 0 : return Shell::ReadCharsFromTcpPort(name, size_out);
2124 : }
2125 :
2126 103792 : FILE* file = FOpen(name, "rb");
2127 103792 : if (file == nullptr) return nullptr;
2128 :
2129 103710 : fseek(file, 0, SEEK_END);
2130 103710 : size_t size = ftell(file);
2131 103710 : rewind(file);
2132 :
2133 103710 : char* chars = new char[size + 1];
2134 103710 : chars[size] = '\0';
2135 311130 : for (size_t i = 0; i < size;) {
2136 207420 : i += fread(&chars[i], 1, size - i, file);
2137 103710 : if (ferror(file)) {
2138 0 : fclose(file);
2139 0 : delete[] chars;
2140 : return nullptr;
2141 : }
2142 : }
2143 103710 : fclose(file);
2144 103710 : *size_out = static_cast<int>(size);
2145 103710 : return chars;
2146 : }
2147 :
2148 :
2149 : struct DataAndPersistent {
2150 : uint8_t* data;
2151 : int byte_length;
2152 : Global<ArrayBuffer> handle;
2153 : };
2154 :
2155 :
2156 3 : static void ReadBufferWeakCallback(
2157 15 : const v8::WeakCallbackInfo<DataAndPersistent>& data) {
2158 3 : int byte_length = data.GetParameter()->byte_length;
2159 : data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
2160 3 : -static_cast<intptr_t>(byte_length));
2161 :
2162 3 : delete[] data.GetParameter()->data;
2163 : data.GetParameter()->handle.Reset();
2164 6 : delete data.GetParameter();
2165 3 : }
2166 :
2167 :
2168 40 : void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
2169 : static_assert(sizeof(char) == sizeof(uint8_t),
2170 : "char and uint8_t should both have 1 byte");
2171 : Isolate* isolate = args.GetIsolate();
2172 20 : String::Utf8Value filename(isolate, args[0]);
2173 : int length;
2174 20 : if (*filename == nullptr) {
2175 0 : Throw(isolate, "Error loading file");
2176 0 : return;
2177 : }
2178 :
2179 20 : DataAndPersistent* data = new DataAndPersistent;
2180 20 : data->data = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length));
2181 20 : if (data->data == nullptr) {
2182 0 : delete data;
2183 0 : Throw(isolate, "Error reading file");
2184 0 : return;
2185 : }
2186 20 : data->byte_length = length;
2187 20 : Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
2188 : data->handle.Reset(isolate, buffer);
2189 : data->handle.SetWeak(data, ReadBufferWeakCallback,
2190 : v8::WeakCallbackType::kParameter);
2191 : data->handle.MarkIndependent();
2192 20 : isolate->AdjustAmountOfExternalAllocatedMemory(length);
2193 :
2194 20 : args.GetReturnValue().Set(buffer);
2195 : }
2196 :
2197 : // Reads a file into a v8 string.
2198 103772 : Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
2199 103772 : int size = 0;
2200 103772 : char* chars = ReadChars(name, &size);
2201 103772 : if (chars == nullptr) return Local<String>();
2202 : Local<String> result;
2203 103690 : if (i::FLAG_use_external_strings && internal::String::IsAscii(chars, size)) {
2204 : String::ExternalOneByteStringResource* resource =
2205 : new ExternalOwningOneByteStringResource(
2206 0 : std::unique_ptr<const char[]>(chars), size);
2207 0 : result = String::NewExternalOneByte(isolate, resource).ToLocalChecked();
2208 : } else {
2209 103690 : result = String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
2210 103690 : .ToLocalChecked();
2211 103690 : delete[] chars;
2212 : }
2213 103690 : return result;
2214 : }
2215 :
2216 :
2217 0 : void Shell::RunShell(Isolate* isolate) {
2218 0 : HandleScope outer_scope(isolate);
2219 : v8::Local<v8::Context> context =
2220 : v8::Local<v8::Context>::New(isolate, evaluation_context_);
2221 : v8::Context::Scope context_scope(context);
2222 0 : PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2223 : Local<String> name =
2224 : String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
2225 0 : .ToLocalChecked();
2226 0 : printf("V8 version %s\n", V8::GetVersion());
2227 : while (true) {
2228 0 : HandleScope inner_scope(isolate);
2229 : printf("d8> ");
2230 0 : Local<String> input = Shell::ReadFromStdin(isolate);
2231 0 : if (input.IsEmpty()) break;
2232 0 : ExecuteString(isolate, input, name, true, true);
2233 0 : }
2234 : printf("\n");
2235 : // We need to explicitly clean up the module embedder data for
2236 : // the interative shell context.
2237 0 : DisposeModuleEmbedderData(context);
2238 0 : }
2239 :
2240 : class InspectorFrontend final : public v8_inspector::V8Inspector::Channel {
2241 : public:
2242 4906 : explicit InspectorFrontend(Local<Context> context) {
2243 2453 : isolate_ = context->GetIsolate();
2244 : context_.Reset(isolate_, context);
2245 2453 : }
2246 4906 : virtual ~InspectorFrontend() = default;
2247 :
2248 : private:
2249 120570 : void sendResponse(
2250 : int callId,
2251 : std::unique_ptr<v8_inspector::StringBuffer> message) override {
2252 120570 : Send(message->string());
2253 120570 : }
2254 109311 : void sendNotification(
2255 : std::unique_ptr<v8_inspector::StringBuffer> message) override {
2256 109311 : Send(message->string());
2257 109311 : }
2258 0 : void flushProtocolNotifications() override {}
2259 :
2260 919524 : void Send(const v8_inspector::StringView& string) {
2261 229881 : v8::Isolate::AllowJavascriptExecutionScope allow_script(isolate_);
2262 229881 : int length = static_cast<int>(string.length());
2263 : DCHECK_LT(length, v8::String::kMaxLength);
2264 : Local<String> message =
2265 : (string.is8Bit()
2266 : ? v8::String::NewFromOneByte(
2267 : isolate_,
2268 : reinterpret_cast<const uint8_t*>(string.characters8()),
2269 0 : v8::NewStringType::kNormal, length)
2270 : : v8::String::NewFromTwoByte(
2271 : isolate_,
2272 : reinterpret_cast<const uint16_t*>(string.characters16()),
2273 229881 : v8::NewStringType::kNormal, length))
2274 459762 : .ToLocalChecked();
2275 : Local<String> callback_name =
2276 229881 : v8::String::NewFromUtf8(isolate_, "receive", v8::NewStringType::kNormal)
2277 229881 : .ToLocalChecked();
2278 229881 : Local<Context> context = context_.Get(isolate_);
2279 : Local<Value> callback =
2280 689643 : context->Global()->Get(context, callback_name).ToLocalChecked();
2281 229881 : if (callback->IsFunction()) {
2282 229881 : v8::TryCatch try_catch(isolate_);
2283 : Local<Value> args[] = {message};
2284 459762 : USE(Local<Function>::Cast(callback)->Call(context, Undefined(isolate_), 1,
2285 229881 : args));
2286 : #ifdef DEBUG
2287 : if (try_catch.HasCaught()) {
2288 : Local<Object> exception = Local<Object>::Cast(try_catch.Exception());
2289 : Local<String> key = v8::String::NewFromUtf8(isolate_, "message",
2290 : v8::NewStringType::kNormal)
2291 : .ToLocalChecked();
2292 : Local<String> expected =
2293 : v8::String::NewFromUtf8(isolate_,
2294 : "Maximum call stack size exceeded",
2295 : v8::NewStringType::kNormal)
2296 : .ToLocalChecked();
2297 : Local<Value> value = exception->Get(context, key).ToLocalChecked();
2298 : DCHECK(value->StrictEquals(expected));
2299 : }
2300 : #endif
2301 229881 : }
2302 229881 : }
2303 :
2304 : Isolate* isolate_;
2305 : Global<Context> context_;
2306 : };
2307 :
2308 88974 : class InspectorClient : public v8_inspector::V8InspectorClient {
2309 : public:
2310 88974 : InspectorClient(Local<Context> context, bool connect) {
2311 86521 : if (!connect) return;
2312 2453 : isolate_ = context->GetIsolate();
2313 4906 : channel_.reset(new InspectorFrontend(context));
2314 4906 : inspector_ = v8_inspector::V8Inspector::create(isolate_, this);
2315 4906 : session_ =
2316 2453 : inspector_->connect(1, channel_.get(), v8_inspector::StringView());
2317 2453 : context->SetAlignedPointerInEmbedderData(kInspectorClientIndex, this);
2318 : inspector_->contextCreated(v8_inspector::V8ContextInfo(
2319 4906 : context, kContextGroupId, v8_inspector::StringView()));
2320 :
2321 : Local<Value> function =
2322 4906 : FunctionTemplate::New(isolate_, SendInspectorMessage)
2323 4906 : ->GetFunction(context)
2324 2453 : .ToLocalChecked();
2325 : Local<String> function_name =
2326 2453 : String::NewFromUtf8(isolate_, "send", NewStringType::kNormal)
2327 2453 : .ToLocalChecked();
2328 7359 : CHECK(context->Global()->Set(context, function_name, function).FromJust());
2329 :
2330 2453 : v8::debug::SetLiveEditEnabled(isolate_, true);
2331 :
2332 2453 : context_.Reset(isolate_, context);
2333 : }
2334 :
2335 : private:
2336 : static v8_inspector::V8InspectorSession* GetSession(Local<Context> context) {
2337 : InspectorClient* inspector_client = static_cast<InspectorClient*>(
2338 : context->GetAlignedPointerFromEmbedderData(kInspectorClientIndex));
2339 : return inspector_client->session_.get();
2340 : }
2341 :
2342 36 : Local<Context> ensureDefaultContextInGroup(int group_id) override {
2343 : DCHECK(isolate_);
2344 : DCHECK_EQ(kContextGroupId, group_id);
2345 72 : return context_.Get(isolate_);
2346 : }
2347 :
2348 120570 : static void SendInspectorMessage(
2349 361710 : const v8::FunctionCallbackInfo<v8::Value>& args) {
2350 : Isolate* isolate = args.GetIsolate();
2351 120570 : v8::HandleScope handle_scope(isolate);
2352 120570 : Local<Context> context = isolate->GetCurrentContext();
2353 : args.GetReturnValue().Set(Undefined(isolate));
2354 120570 : Local<String> message = args[0]->ToString(context).ToLocalChecked();
2355 : v8_inspector::V8InspectorSession* session =
2356 : InspectorClient::GetSession(context);
2357 120570 : int length = message->Length();
2358 120570 : std::unique_ptr<uint16_t[]> buffer(new uint16_t[length]);
2359 120570 : message->Write(buffer.get(), 0, length);
2360 : v8_inspector::StringView message_view(buffer.get(), length);
2361 120570 : session->dispatchProtocolMessage(message_view);
2362 120570 : args.GetReturnValue().Set(True(isolate));
2363 120570 : }
2364 :
2365 : static const int kContextGroupId = 1;
2366 :
2367 : std::unique_ptr<v8_inspector::V8Inspector> inspector_;
2368 : std::unique_ptr<v8_inspector::V8InspectorSession> session_;
2369 : std::unique_ptr<v8_inspector::V8Inspector::Channel> channel_;
2370 : Global<Context> context_;
2371 : Isolate* isolate_;
2372 : };
2373 :
2374 53566 : SourceGroup::~SourceGroup() {
2375 26783 : delete thread_;
2376 26783 : thread_ = nullptr;
2377 26783 : }
2378 :
2379 :
2380 44487 : void SourceGroup::Execute(Isolate* isolate) {
2381 : bool exception_was_thrown = false;
2382 139775 : for (int i = begin_offset_; i < end_offset_; ++i) {
2383 96649 : const char* arg = argv_[i];
2384 96649 : if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
2385 : // Execute argument given to -e option directly.
2386 1500 : HandleScope handle_scope(isolate);
2387 : Local<String> file_name =
2388 : String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
2389 1500 : .ToLocalChecked();
2390 : Local<String> source =
2391 1500 : String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
2392 3000 : .ToLocalChecked();
2393 1500 : Shell::options.script_executed = true;
2394 1500 : if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
2395 : exception_was_thrown = true;
2396 1341 : break;
2397 : }
2398 : ++i;
2399 159 : continue;
2400 95149 : } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
2401 : // Treat the next file as a module.
2402 461 : arg = argv_[++i];
2403 461 : Shell::options.script_executed = true;
2404 461 : if (!Shell::ExecuteModule(isolate, arg)) {
2405 : exception_was_thrown = true;
2406 : break;
2407 : }
2408 : continue;
2409 94688 : } else if (arg[0] == '-') {
2410 : // Ignore other options. They have been parsed already.
2411 : continue;
2412 : }
2413 :
2414 : // Use all other arguments as names of files to load and run.
2415 93757 : HandleScope handle_scope(isolate);
2416 : Local<String> file_name =
2417 : String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
2418 93757 : .ToLocalChecked();
2419 : Local<String> source = ReadFile(isolate, arg);
2420 93757 : if (source.IsEmpty()) {
2421 : printf("Error reading '%s'\n", arg);
2422 0 : Shell::Exit(1);
2423 : }
2424 93757 : Shell::options.script_executed = true;
2425 93757 : if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
2426 : exception_was_thrown = true;
2427 20 : break;
2428 : }
2429 93737 : }
2430 44487 : if (exception_was_thrown != Shell::options.expected_to_throw) {
2431 0 : Shell::Exit(1);
2432 : }
2433 44487 : }
2434 :
2435 0 : Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
2436 93757 : return Shell::ReadFile(isolate, name);
2437 : }
2438 :
2439 :
2440 0 : base::Thread::Options SourceGroup::GetThreadOptions() {
2441 : // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
2442 : // which is not enough to parse the big literal expressions used in tests.
2443 : // The stack size should be at least StackGuard::kLimitSize + some
2444 : // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
2445 0 : return base::Thread::Options("IsolateThread", 2 * MB);
2446 : }
2447 :
2448 0 : void SourceGroup::ExecuteInThread() {
2449 : Isolate::CreateParams create_params;
2450 0 : create_params.array_buffer_allocator = Shell::array_buffer_allocator;
2451 0 : Isolate* isolate = Isolate::New(create_params);
2452 : isolate->SetHostImportModuleDynamicallyCallback(
2453 0 : Shell::HostImportModuleDynamically);
2454 : isolate->SetHostInitializeImportMetaObjectCallback(
2455 0 : Shell::HostInitializeImportMetaObject);
2456 :
2457 0 : Shell::EnsureEventLoopInitialized(isolate);
2458 0 : D8Console console(isolate);
2459 0 : debug::SetConsoleDelegate(isolate, &console);
2460 0 : for (int i = 0; i < Shell::options.stress_runs; ++i) {
2461 0 : next_semaphore_.Wait();
2462 : {
2463 : Isolate::Scope iscope(isolate);
2464 0 : PerIsolateData data(isolate);
2465 : {
2466 0 : HandleScope scope(isolate);
2467 0 : Local<Context> context = Shell::CreateEvaluationContext(isolate);
2468 : {
2469 : Context::Scope cscope(context);
2470 : InspectorClient inspector_client(context,
2471 0 : Shell::options.enable_inspector);
2472 0 : PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2473 0 : Execute(isolate);
2474 : }
2475 0 : DisposeModuleEmbedderData(context);
2476 : }
2477 0 : Shell::CollectGarbage(isolate);
2478 0 : Shell::CompleteMessageLoop(isolate);
2479 : }
2480 0 : done_semaphore_.Signal();
2481 : }
2482 :
2483 0 : isolate->Dispose();
2484 0 : }
2485 :
2486 :
2487 0 : void SourceGroup::StartExecuteInThread() {
2488 0 : if (thread_ == nullptr) {
2489 0 : thread_ = new IsolateThread(this);
2490 0 : thread_->Start();
2491 : }
2492 0 : next_semaphore_.Signal();
2493 0 : }
2494 :
2495 :
2496 0 : void SourceGroup::WaitForThread() {
2497 0 : if (thread_ == nullptr) return;
2498 0 : done_semaphore_.Wait();
2499 : }
2500 :
2501 :
2502 0 : void SourceGroup::JoinThread() {
2503 0 : if (thread_ == nullptr) return;
2504 0 : thread_->Join();
2505 : }
2506 :
2507 0 : ExternalizedContents::~ExternalizedContents() {
2508 239 : Shell::array_buffer_allocator->Free(data_, size_);
2509 0 : }
2510 :
2511 1695 : void SerializationDataQueue::Enqueue(std::unique_ptr<SerializationData> data) {
2512 1695 : base::LockGuard<base::Mutex> lock_guard(&mutex_);
2513 1695 : data_.push_back(std::move(data));
2514 1695 : }
2515 :
2516 1189 : bool SerializationDataQueue::Dequeue(
2517 : std::unique_ptr<SerializationData>* out_data) {
2518 : out_data->reset();
2519 1189 : base::LockGuard<base::Mutex> lock_guard(&mutex_);
2520 1189 : if (data_.empty()) return false;
2521 : *out_data = std::move(data_[0]);
2522 961 : data_.erase(data_.begin());
2523 961 : return true;
2524 : }
2525 :
2526 :
2527 0 : bool SerializationDataQueue::IsEmpty() {
2528 0 : base::LockGuard<base::Mutex> lock_guard(&mutex_);
2529 0 : return data_.empty();
2530 : }
2531 :
2532 :
2533 774 : void SerializationDataQueue::Clear() {
2534 774 : base::LockGuard<base::Mutex> lock_guard(&mutex_);
2535 : data_.clear();
2536 774 : }
2537 :
2538 387 : Worker::Worker()
2539 : : in_semaphore_(0),
2540 : out_semaphore_(0),
2541 : thread_(nullptr),
2542 : script_(nullptr),
2543 774 : running_(false) {}
2544 :
2545 774 : Worker::~Worker() {
2546 387 : delete thread_;
2547 387 : thread_ = nullptr;
2548 387 : delete[] script_;
2549 387 : script_ = nullptr;
2550 387 : in_queue_.Clear();
2551 387 : out_queue_.Clear();
2552 387 : }
2553 :
2554 :
2555 387 : void Worker::StartExecuteInThread(const char* script) {
2556 387 : running_ = true;
2557 387 : script_ = i::StrDup(script);
2558 774 : thread_ = new WorkerThread(this);
2559 387 : thread_->Start();
2560 387 : }
2561 :
2562 1011 : void Worker::PostMessage(std::unique_ptr<SerializationData> data) {
2563 2022 : in_queue_.Enqueue(std::move(data));
2564 1011 : in_semaphore_.Signal();
2565 1011 : }
2566 :
2567 327 : std::unique_ptr<SerializationData> Worker::GetMessage() {
2568 327 : std::unique_ptr<SerializationData> result;
2569 872 : while (!out_queue_.Dequeue(&result)) {
2570 : // If the worker is no longer running, and there are no messages in the
2571 : // queue, don't expect any more messages from it.
2572 456 : if (!base::Relaxed_Load(&running_)) break;
2573 218 : out_semaphore_.Wait();
2574 : }
2575 327 : return result;
2576 : }
2577 :
2578 :
2579 604 : void Worker::Terminate() {
2580 604 : base::Relaxed_Store(&running_, false);
2581 : // Post nullptr to wake the Worker thread message loop, and tell it to stop
2582 : // running.
2583 1208 : PostMessage(nullptr);
2584 604 : }
2585 :
2586 :
2587 0 : void Worker::WaitForThread() {
2588 387 : Terminate();
2589 387 : thread_->Join();
2590 0 : }
2591 :
2592 :
2593 387 : void Worker::ExecuteInThread() {
2594 : Isolate::CreateParams create_params;
2595 387 : create_params.array_buffer_allocator = Shell::array_buffer_allocator;
2596 387 : Isolate* isolate = Isolate::New(create_params);
2597 : isolate->SetHostImportModuleDynamicallyCallback(
2598 387 : Shell::HostImportModuleDynamically);
2599 : isolate->SetHostInitializeImportMetaObjectCallback(
2600 387 : Shell::HostInitializeImportMetaObject);
2601 387 : D8Console console(isolate);
2602 387 : debug::SetConsoleDelegate(isolate, &console);
2603 : {
2604 : Isolate::Scope iscope(isolate);
2605 : {
2606 387 : HandleScope scope(isolate);
2607 774 : PerIsolateData data(isolate);
2608 387 : Local<Context> context = Shell::CreateEvaluationContext(isolate);
2609 : {
2610 : Context::Scope cscope(context);
2611 774 : PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2612 :
2613 387 : Local<Object> global = context->Global();
2614 387 : Local<Value> this_value = External::New(isolate, this);
2615 : Local<FunctionTemplate> postmessage_fun_template =
2616 387 : FunctionTemplate::New(isolate, PostMessageOut, this_value);
2617 :
2618 : Local<Function> postmessage_fun;
2619 387 : if (postmessage_fun_template->GetFunction(context)
2620 387 : .ToLocal(&postmessage_fun)) {
2621 : global->Set(context, String::NewFromUtf8(isolate, "postMessage",
2622 : NewStringType::kNormal)
2623 : .ToLocalChecked(),
2624 1161 : postmessage_fun).FromJust();
2625 : }
2626 :
2627 : // First run the script
2628 : Local<String> file_name =
2629 : String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
2630 387 : .ToLocalChecked();
2631 : Local<String> source =
2632 387 : String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
2633 774 : .ToLocalChecked();
2634 387 : if (Shell::ExecuteString(isolate, source, file_name, false, true)) {
2635 : // Get the message handler
2636 : Local<Value> onmessage =
2637 : global->Get(context, String::NewFromUtf8(isolate, "onmessage",
2638 : NewStringType::kNormal)
2639 1161 : .ToLocalChecked()).ToLocalChecked();
2640 387 : if (onmessage->IsFunction()) {
2641 : Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
2642 : // Now wait for messages
2643 : while (true) {
2644 643 : in_semaphore_.Wait();
2645 644 : std::unique_ptr<SerializationData> data;
2646 644 : if (!in_queue_.Dequeue(&data)) continue;
2647 644 : if (!data) {
2648 : break;
2649 : }
2650 713 : v8::TryCatch try_catch(isolate);
2651 : Local<Value> value;
2652 357 : if (Shell::DeserializeValue(isolate, std::move(data))
2653 357 : .ToLocal(&value)) {
2654 357 : Local<Value> argv[] = {value};
2655 357 : (void)onmessage_fun->Call(context, global, 1, argv);
2656 : }
2657 356 : if (try_catch.HasCaught()) {
2658 10 : Shell::ReportException(isolate, &try_catch);
2659 : }
2660 : }
2661 : }
2662 : }
2663 : }
2664 774 : DisposeModuleEmbedderData(context);
2665 : }
2666 387 : Shell::CollectGarbage(isolate);
2667 : }
2668 387 : isolate->Dispose();
2669 :
2670 : // Post nullptr to wake the thread waiting on GetMessage() if there is one.
2671 774 : out_queue_.Enqueue(nullptr);
2672 387 : out_semaphore_.Signal();
2673 387 : }
2674 :
2675 :
2676 888 : void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
2677 : Isolate* isolate = args.GetIsolate();
2678 296 : HandleScope handle_scope(isolate);
2679 :
2680 296 : if (args.Length() < 1) {
2681 0 : Throw(isolate, "Invalid argument");
2682 297 : return;
2683 : }
2684 :
2685 296 : Local<Value> message = args[0];
2686 : Local<Value> transfer = Undefined(isolate);
2687 : std::unique_ptr<SerializationData> data =
2688 296 : Shell::SerializeValue(isolate, message, transfer);
2689 296 : if (data) {
2690 : DCHECK(args.Data()->IsExternal());
2691 : Local<External> this_value = Local<External>::Cast(args.Data());
2692 296 : Worker* worker = static_cast<Worker*>(this_value->Value());
2693 594 : worker->out_queue_.Enqueue(std::move(data));
2694 297 : worker->out_semaphore_.Signal();
2695 296 : }
2696 : }
2697 :
2698 :
2699 80349 : void SetFlagsFromString(const char* flags) {
2700 80349 : v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
2701 80349 : }
2702 :
2703 :
2704 26783 : bool Shell::SetOptions(int argc, char* argv[]) {
2705 : bool logfile_per_isolate = false;
2706 249022 : for (int i = 0; i < argc; i++) {
2707 222239 : if (strcmp(argv[i], "--stress-opt") == 0) {
2708 4531 : options.stress_opt = true;
2709 4531 : argv[i] = nullptr;
2710 435333 : } else if (strcmp(argv[i], "--nostress-opt") == 0 ||
2711 217625 : strcmp(argv[i], "--no-stress-opt") == 0) {
2712 248 : options.stress_opt = false;
2713 248 : argv[i] = nullptr;
2714 217460 : } else if (strcmp(argv[i], "--stress-deopt") == 0) {
2715 0 : options.stress_deopt = true;
2716 0 : argv[i] = nullptr;
2717 217460 : } else if (strcmp(argv[i], "--mock-arraybuffer-allocator") == 0) {
2718 23 : options.mock_arraybuffer_allocator = true;
2719 23 : argv[i] = nullptr;
2720 434768 : } else if (strcmp(argv[i], "--noalways-opt") == 0 ||
2721 217331 : strcmp(argv[i], "--no-always-opt") == 0) {
2722 : // No support for stressing if we can't use --always-opt.
2723 542 : options.stress_opt = false;
2724 542 : options.stress_deopt = false;
2725 216895 : } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
2726 : logfile_per_isolate = true;
2727 0 : argv[i] = nullptr;
2728 216895 : } else if (strcmp(argv[i], "--shell") == 0) {
2729 0 : options.interactive_shell = true;
2730 0 : argv[i] = nullptr;
2731 216895 : } else if (strcmp(argv[i], "--test") == 0) {
2732 26783 : options.test_shell = true;
2733 26783 : argv[i] = nullptr;
2734 380224 : } else if (strcmp(argv[i], "--notest") == 0 ||
2735 190112 : strcmp(argv[i], "--no-test") == 0) {
2736 12 : options.test_shell = false;
2737 12 : argv[i] = nullptr;
2738 190100 : } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
2739 11 : options.send_idle_notification = true;
2740 11 : argv[i] = nullptr;
2741 190089 : } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
2742 2691 : options.invoke_weak_callbacks = true;
2743 : // TODO(jochen) See issue 3351
2744 2691 : options.send_idle_notification = true;
2745 2691 : argv[i] = nullptr;
2746 187398 : } else if (strcmp(argv[i], "--omit-quit") == 0) {
2747 17 : options.omit_quit = true;
2748 17 : argv[i] = nullptr;
2749 187381 : } else if (strcmp(argv[i], "-f") == 0) {
2750 : // Ignore any -f flags for compatibility with other stand-alone
2751 : // JavaScript engines.
2752 : continue;
2753 187381 : } else if (strcmp(argv[i], "--isolate") == 0) {
2754 0 : options.num_isolates++;
2755 187381 : } else if (strcmp(argv[i], "--throws") == 0) {
2756 1353 : options.expected_to_throw = true;
2757 1353 : argv[i] = nullptr;
2758 186028 : } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
2759 0 : options.icu_data_file = argv[i] + 16;
2760 0 : argv[i] = nullptr;
2761 : #ifdef V8_USE_EXTERNAL_STARTUP_DATA
2762 186028 : } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
2763 0 : options.natives_blob = argv[i] + 15;
2764 0 : argv[i] = nullptr;
2765 186028 : } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
2766 0 : options.snapshot_blob = argv[i] + 16;
2767 0 : argv[i] = nullptr;
2768 : #endif // V8_USE_EXTERNAL_STARTUP_DATA
2769 372056 : } else if (strcmp(argv[i], "--cache") == 0 ||
2770 186028 : strncmp(argv[i], "--cache=", 8) == 0) {
2771 64 : const char* value = argv[i] + 7;
2772 64 : if (!*value || strncmp(value, "=code", 6) == 0) {
2773 64 : options.compile_options = v8::ScriptCompiler::kProduceCodeCache;
2774 0 : } else if (strncmp(value, "=parse", 7) == 0) {
2775 0 : options.compile_options = v8::ScriptCompiler::kProduceParserCache;
2776 0 : } else if (strncmp(value, "=none", 6) == 0) {
2777 0 : options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
2778 : } else {
2779 : printf("Unknown option to --cache.\n");
2780 0 : return false;
2781 : }
2782 64 : argv[i] = nullptr;
2783 185964 : } else if (strcmp(argv[i], "--enable-tracing") == 0) {
2784 0 : options.trace_enabled = true;
2785 0 : argv[i] = nullptr;
2786 185964 : } else if (strncmp(argv[i], "--trace-config=", 15) == 0) {
2787 0 : options.trace_config = argv[i] + 15;
2788 0 : argv[i] = nullptr;
2789 185964 : } else if (strcmp(argv[i], "--enable-inspector") == 0) {
2790 1423 : options.enable_inspector = true;
2791 1423 : argv[i] = nullptr;
2792 184541 : } else if (strncmp(argv[i], "--lcov=", 7) == 0) {
2793 0 : options.lcov_file = argv[i] + 7;
2794 0 : argv[i] = nullptr;
2795 184541 : } else if (strcmp(argv[i], "--disable-in-process-stack-traces") == 0) {
2796 0 : options.disable_in_process_stack_traces = true;
2797 0 : argv[i] = nullptr;
2798 : #ifdef V8_OS_POSIX
2799 184541 : } else if (strncmp(argv[i], "--read-from-tcp-port=", 21) == 0) {
2800 0 : options.read_from_tcp_port = atoi(argv[i] + 21);
2801 0 : argv[i] = nullptr;
2802 : #endif // V8_OS_POSIX
2803 184541 : } else if (strcmp(argv[i], "--enable-os-system") == 0) {
2804 0 : options.enable_os_system = true;
2805 0 : argv[i] = nullptr;
2806 : }
2807 : }
2808 :
2809 26783 : v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
2810 :
2811 : // Set up isolated source groups.
2812 26783 : options.isolate_sources = new SourceGroup[options.num_isolates];
2813 : SourceGroup* current = options.isolate_sources;
2814 : current->Begin(argv, 1);
2815 85757 : for (int i = 1; i < argc; i++) {
2816 58974 : const char* str = argv[i];
2817 58974 : if (strcmp(str, "--isolate") == 0) {
2818 : current->End(i);
2819 0 : current++;
2820 0 : current->Begin(argv, i + 1);
2821 58974 : } else if (strcmp(str, "--module") == 0) {
2822 : // Pass on to SourceGroup, which understands this option.
2823 58697 : } else if (strncmp(argv[i], "--", 2) == 0) {
2824 : printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
2825 58136 : } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
2826 1492 : options.script_executed = true;
2827 56644 : } else if (strncmp(str, "-", 1) != 0) {
2828 : // Not a flag, so it must be a script to execute.
2829 56638 : options.script_executed = true;
2830 : }
2831 : }
2832 : current->End(argc);
2833 :
2834 26783 : if (!logfile_per_isolate && options.num_isolates) {
2835 26783 : SetFlagsFromString("--nologfile_per_isolate");
2836 : }
2837 :
2838 : return true;
2839 : }
2840 :
2841 :
2842 44487 : int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
2843 44487 : for (int i = 1; i < options.num_isolates; ++i) {
2844 0 : options.isolate_sources[i].StartExecuteInThread();
2845 : }
2846 : {
2847 44487 : EnsureEventLoopInitialized(isolate);
2848 44487 : if (options.lcov_file) {
2849 0 : debug::Coverage::SelectMode(isolate, debug::Coverage::kBlockCount);
2850 : }
2851 44487 : HandleScope scope(isolate);
2852 44487 : Local<Context> context = CreateEvaluationContext(isolate);
2853 71270 : bool use_existing_context = last_run && options.use_interactive_shell();
2854 44487 : if (use_existing_context) {
2855 : // Keep using the same context in the interactive shell.
2856 : evaluation_context_.Reset(isolate, context);
2857 : }
2858 : {
2859 : Context::Scope cscope(context);
2860 88974 : InspectorClient inspector_client(context, options.enable_inspector);
2861 88974 : PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2862 44487 : options.isolate_sources[0].Execute(isolate);
2863 : }
2864 44487 : if (!use_existing_context) {
2865 44487 : DisposeModuleEmbedderData(context);
2866 : }
2867 44487 : WriteLcovData(isolate, options.lcov_file);
2868 : }
2869 44487 : CollectGarbage(isolate);
2870 44487 : CompleteMessageLoop(isolate);
2871 44487 : for (int i = 1; i < options.num_isolates; ++i) {
2872 0 : if (last_run) {
2873 0 : options.isolate_sources[i].JoinThread();
2874 : } else {
2875 0 : options.isolate_sources[i].WaitForThread();
2876 : }
2877 : }
2878 44487 : CleanupWorkers();
2879 44487 : return 0;
2880 : }
2881 :
2882 :
2883 71657 : void Shell::CollectGarbage(Isolate* isolate) {
2884 71657 : if (options.send_idle_notification) {
2885 : const double kLongIdlePauseInSeconds = 1.0;
2886 5510 : isolate->ContextDisposedNotification();
2887 : isolate->IdleNotificationDeadline(
2888 5510 : g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
2889 : }
2890 71657 : if (options.invoke_weak_callbacks) {
2891 : // By sending a low memory notifications, we will try hard to collect all
2892 : // garbage and will therefore also invoke all weak callbacks of actually
2893 : // unreachable persistent handles.
2894 5455 : isolate->LowMemoryNotification();
2895 : }
2896 71657 : }
2897 :
2898 44487 : void Shell::EnsureEventLoopInitialized(Isolate* isolate) {
2899 44487 : v8::platform::EnsureEventLoopInitialized(GetDefaultPlatform(), isolate);
2900 44487 : SetWaitUntilDone(isolate, false);
2901 44487 : }
2902 :
2903 45557 : void Shell::SetWaitUntilDone(Isolate* isolate, bool value) {
2904 : base::LockGuard<base::Mutex> guard(isolate_status_lock_.Pointer());
2905 45557 : if (isolate_status_.count(isolate) == 0) {
2906 53566 : isolate_status_.insert(std::make_pair(isolate, value));
2907 : } else {
2908 18774 : isolate_status_[isolate] = value;
2909 : }
2910 45557 : }
2911 :
2912 : namespace {
2913 148189 : void ProcessMessages(Isolate* isolate,
2914 : std::function<platform::MessageLoopBehavior()> behavior) {
2915 : Platform* platform = GetDefaultPlatform();
2916 : while (true) {
2917 183602 : while (v8::platform::PumpMessageLoop(platform, isolate, behavior())) {
2918 35359 : isolate->RunMicrotasks();
2919 : }
2920 148243 : if (platform->IdleTasksEnabled(isolate)) {
2921 : v8::platform::RunIdleTasks(platform, isolate,
2922 148243 : 50.0 / base::Time::kMillisecondsPerSecond);
2923 : }
2924 148243 : HandleScope handle_scope(isolate);
2925 : PerIsolateData* data = PerIsolateData::Get(isolate);
2926 : Local<Function> callback;
2927 296486 : if (!data->GetTimeoutCallback().ToLocal(&callback)) break;
2928 : Local<Context> context;
2929 120 : if (!data->GetTimeoutContext().ToLocal(&context)) break;
2930 114 : TryCatch try_catch(isolate);
2931 60 : try_catch.SetVerbose(true);
2932 : Context::Scope context_scope(context);
2933 120 : if (callback->Call(context, Undefined(isolate), 0, nullptr).IsEmpty()) {
2934 6 : Shell::ReportException(isolate, &try_catch);
2935 148189 : return;
2936 : }
2937 54 : }
2938 : }
2939 : } // anonymous namespace
2940 :
2941 44487 : void Shell::CompleteMessageLoop(Isolate* isolate) {
2942 45308 : ProcessMessages(isolate, [isolate]() {
2943 : base::LockGuard<base::Mutex> guard(isolate_status_lock_.Pointer());
2944 : DCHECK_GT(isolate_status_.count(isolate), 0);
2945 45308 : return isolate_status_[isolate]
2946 : ? platform::MessageLoopBehavior::kWaitForWork
2947 90616 : : platform::MessageLoopBehavior::kDoNotWait;
2948 88974 : });
2949 44487 : }
2950 :
2951 103702 : void Shell::EmptyMessageQueues(Isolate* isolate) {
2952 : ProcessMessages(isolate,
2953 207404 : []() { return platform::MessageLoopBehavior::kDoNotWait; });
2954 103702 : }
2955 :
2956 2639 : class Serializer : public ValueSerializer::Delegate {
2957 : public:
2958 880 : explicit Serializer(Isolate* isolate)
2959 : : isolate_(isolate),
2960 : serializer_(isolate, this),
2961 1760 : current_memory_usage_(0) {}
2962 :
2963 880 : Maybe<bool> WriteValue(Local<Context> context, Local<Value> value,
2964 : Local<Value> transfer) {
2965 : bool ok;
2966 : DCHECK(!data_);
2967 880 : data_.reset(new SerializationData);
2968 1760 : if (!PrepareTransfer(context, transfer).To(&ok)) {
2969 : return Nothing<bool>();
2970 : }
2971 725 : serializer_.WriteHeader();
2972 :
2973 1448 : if (!serializer_.WriteValue(context, value).To(&ok)) {
2974 : data_.reset();
2975 : return Nothing<bool>();
2976 : }
2977 :
2978 1406 : if (!FinalizeTransfer().To(&ok)) {
2979 : return Nothing<bool>();
2980 : }
2981 :
2982 703 : std::pair<uint8_t*, size_t> pair = serializer_.Release();
2983 703 : data_->data_.reset(pair.first);
2984 703 : data_->size_ = pair.second;
2985 : return Just(true);
2986 : }
2987 :
2988 : std::unique_ptr<SerializationData> Release() { return std::move(data_); }
2989 :
2990 : protected:
2991 : // Implements ValueSerializer::Delegate.
2992 11 : void ThrowDataCloneError(Local<String> message) override {
2993 11 : isolate_->ThrowException(Exception::Error(message));
2994 11 : }
2995 :
2996 207 : Maybe<uint32_t> GetSharedArrayBufferId(
2997 : Isolate* isolate, Local<SharedArrayBuffer> shared_array_buffer) override {
2998 : DCHECK_NOT_NULL(data_);
2999 414 : for (size_t index = 0; index < shared_array_buffers_.size(); ++index) {
3000 207 : if (shared_array_buffers_[index] == shared_array_buffer) {
3001 0 : return Just<uint32_t>(static_cast<uint32_t>(index));
3002 : }
3003 : }
3004 :
3005 : size_t index = shared_array_buffers_.size();
3006 207 : shared_array_buffers_.emplace_back(isolate_, shared_array_buffer);
3007 207 : return Just<uint32_t>(static_cast<uint32_t>(index));
3008 : }
3009 :
3010 725 : void* ReallocateBufferMemory(void* old_buffer, size_t size,
3011 : size_t* actual_size) override {
3012 : // Not accurate, because we don't take into account reallocated buffers,
3013 : // but this is fine for testing.
3014 725 : current_memory_usage_ += size;
3015 725 : if (current_memory_usage_ > kMaxSerializerMemoryUsage) return nullptr;
3016 :
3017 725 : void* result = realloc(old_buffer, size);
3018 725 : *actual_size = result ? size : 0;
3019 725 : return result;
3020 : }
3021 :
3022 21 : void FreeBufferMemory(void* buffer) override { free(buffer); }
3023 :
3024 : private:
3025 880 : Maybe<bool> PrepareTransfer(Local<Context> context, Local<Value> transfer) {
3026 880 : if (transfer->IsArray()) {
3027 : Local<Array> transfer_array = Local<Array>::Cast(transfer);
3028 175 : uint32_t length = transfer_array->Length();
3029 20 : for (uint32_t i = 0; i < length; ++i) {
3030 : Local<Value> element;
3031 350 : if (transfer_array->Get(context, i).ToLocal(&element)) {
3032 165 : if (!element->IsArrayBuffer()) {
3033 145 : Throw(isolate_, "Transfer array elements must be an ArrayBuffer");
3034 145 : return Nothing<bool>();
3035 : }
3036 :
3037 20 : Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(element);
3038 : serializer_.TransferArrayBuffer(
3039 40 : static_cast<uint32_t>(array_buffers_.size()), array_buffer);
3040 20 : array_buffers_.emplace_back(isolate_, array_buffer);
3041 : } else {
3042 : return Nothing<bool>();
3043 : }
3044 : }
3045 : return Just(true);
3046 705 : } else if (transfer->IsUndefined()) {
3047 : return Just(true);
3048 : } else {
3049 0 : Throw(isolate_, "Transfer list must be an Array or undefined");
3050 : return Nothing<bool>();
3051 : }
3052 : }
3053 :
3054 : template <typename T>
3055 227 : typename T::Contents MaybeExternalize(Local<T> array_buffer) {
3056 227 : if (array_buffer->IsExternal()) {
3057 121 : return array_buffer->GetContents();
3058 : } else {
3059 106 : typename T::Contents contents = array_buffer->Externalize();
3060 106 : data_->externalized_contents_.emplace_back(contents);
3061 106 : return contents;
3062 : }
3063 : }
3064 :
3065 703 : Maybe<bool> FinalizeTransfer() {
3066 1426 : for (const auto& global_array_buffer : array_buffers_) {
3067 : Local<ArrayBuffer> array_buffer =
3068 20 : Local<ArrayBuffer>::New(isolate_, global_array_buffer);
3069 20 : if (!array_buffer->IsNeuterable()) {
3070 0 : Throw(isolate_, "ArrayBuffer could not be transferred");
3071 0 : return Nothing<bool>();
3072 : }
3073 :
3074 20 : ArrayBuffer::Contents contents = MaybeExternalize(array_buffer);
3075 20 : array_buffer->Neuter();
3076 20 : data_->array_buffer_contents_.push_back(contents);
3077 : }
3078 :
3079 1613 : for (const auto& global_shared_array_buffer : shared_array_buffers_) {
3080 : Local<SharedArrayBuffer> shared_array_buffer =
3081 414 : Local<SharedArrayBuffer>::New(isolate_, global_shared_array_buffer);
3082 : data_->shared_array_buffer_contents_.push_back(
3083 621 : MaybeExternalize(shared_array_buffer));
3084 : }
3085 :
3086 : return Just(true);
3087 : }
3088 :
3089 : Isolate* isolate_;
3090 : ValueSerializer serializer_;
3091 : std::unique_ptr<SerializationData> data_;
3092 : std::vector<Global<ArrayBuffer>> array_buffers_;
3093 : std::vector<Global<SharedArrayBuffer>> shared_array_buffers_;
3094 : size_t current_memory_usage_;
3095 :
3096 : DISALLOW_COPY_AND_ASSIGN(Serializer);
3097 : };
3098 :
3099 1962 : class Deserializer : public ValueDeserializer::Delegate {
3100 : public:
3101 654 : Deserializer(Isolate* isolate, std::unique_ptr<SerializationData> data)
3102 : : isolate_(isolate),
3103 : deserializer_(isolate, data->data(), data->size(), this),
3104 1962 : data_(std::move(data)) {
3105 654 : deserializer_.SetSupportsLegacyWireFormat(true);
3106 654 : }
3107 :
3108 654 : MaybeLocal<Value> ReadValue(Local<Context> context) {
3109 : bool read_header;
3110 1308 : if (!deserializer_.ReadHeader(context).To(&read_header)) {
3111 0 : return MaybeLocal<Value>();
3112 : }
3113 :
3114 : uint32_t index = 0;
3115 1328 : for (const auto& contents : data_->array_buffer_contents()) {
3116 : Local<ArrayBuffer> array_buffer =
3117 20 : ArrayBuffer::New(isolate_, contents.Data(), contents.ByteLength());
3118 20 : deserializer_.TransferArrayBuffer(index++, array_buffer);
3119 : }
3120 :
3121 : index = 0;
3122 1515 : for (const auto& contents : data_->shared_array_buffer_contents()) {
3123 : Local<SharedArrayBuffer> shared_array_buffer = SharedArrayBuffer::New(
3124 207 : isolate_, contents.Data(), contents.ByteLength());
3125 207 : deserializer_.TransferSharedArrayBuffer(index++, shared_array_buffer);
3126 : }
3127 :
3128 654 : return deserializer_.ReadValue(context);
3129 : }
3130 :
3131 : private:
3132 : Isolate* isolate_;
3133 : ValueDeserializer deserializer_;
3134 : std::unique_ptr<SerializationData> data_;
3135 :
3136 : DISALLOW_COPY_AND_ASSIGN(Deserializer);
3137 : };
3138 :
3139 879 : std::unique_ptr<SerializationData> Shell::SerializeValue(
3140 : Isolate* isolate, Local<Value> value, Local<Value> transfer) {
3141 : bool ok;
3142 879 : Local<Context> context = isolate->GetCurrentContext();
3143 880 : Serializer serializer(isolate);
3144 1759 : if (serializer.WriteValue(context, value, transfer).To(&ok)) {
3145 : std::unique_ptr<SerializationData> data = serializer.Release();
3146 : base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
3147 704 : data->AppendExternalizedContentsTo(&externalized_contents_);
3148 : return data;
3149 : }
3150 880 : return nullptr;
3151 : }
3152 :
3153 654 : MaybeLocal<Value> Shell::DeserializeValue(
3154 : Isolate* isolate, std::unique_ptr<SerializationData> data) {
3155 : Local<Value> value;
3156 654 : Local<Context> context = isolate->GetCurrentContext();
3157 1308 : Deserializer deserializer(isolate, std::move(data));
3158 654 : return deserializer.ReadValue(context);
3159 : }
3160 :
3161 :
3162 44487 : void Shell::CleanupWorkers() {
3163 : // Make a copy of workers_, because we don't want to call Worker::Terminate
3164 : // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
3165 : // create a new Worker, it would deadlock.
3166 : std::vector<Worker*> workers_copy;
3167 : {
3168 : base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
3169 44487 : allow_new_workers_ = false;
3170 : workers_copy.swap(workers_);
3171 : }
3172 :
3173 89361 : for (Worker* worker : workers_copy) {
3174 : worker->WaitForThread();
3175 387 : delete worker;
3176 : }
3177 :
3178 : // Now that all workers are terminated, we can re-enable Worker creation.
3179 : base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
3180 44487 : allow_new_workers_ = true;
3181 : externalized_contents_.clear();
3182 44487 : }
3183 :
3184 26783 : int Shell::Main(int argc, char* argv[]) {
3185 26783 : std::ofstream trace_file;
3186 : #if (defined(_WIN32) || defined(_WIN64))
3187 : UINT new_flags =
3188 : SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
3189 : UINT existing_flags = SetErrorMode(new_flags);
3190 : SetErrorMode(existing_flags | new_flags);
3191 : #if defined(_MSC_VER)
3192 : _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
3193 : _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
3194 : _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
3195 : _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
3196 : _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
3197 : _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
3198 : _set_error_mode(_OUT_TO_STDERR);
3199 : #endif // defined(_MSC_VER)
3200 : #endif // defined(_WIN32) || defined(_WIN64)
3201 26783 : if (!SetOptions(argc, argv)) return 1;
3202 26783 : v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
3203 :
3204 : v8::platform::InProcessStackDumping in_process_stack_dumping =
3205 : options.disable_in_process_stack_traces
3206 : ? v8::platform::InProcessStackDumping::kDisabled
3207 26783 : : v8::platform::InProcessStackDumping::kEnabled;
3208 :
3209 : platform::tracing::TracingController* tracing_controller = nullptr;
3210 26783 : if (options.trace_enabled && !i::FLAG_verify_predictable) {
3211 0 : trace_file.open("v8_trace.json");
3212 0 : tracing_controller = new platform::tracing::TracingController();
3213 : platform::tracing::TraceBuffer* trace_buffer =
3214 : platform::tracing::TraceBuffer::CreateTraceBufferRingBuffer(
3215 : platform::tracing::TraceBuffer::kRingBufferChunks,
3216 0 : platform::tracing::TraceWriter::CreateJSONTraceWriter(trace_file));
3217 0 : tracing_controller->Initialize(trace_buffer);
3218 : }
3219 :
3220 : g_platform = v8::platform::CreateDefaultPlatform(
3221 : 0, v8::platform::IdleTaskSupport::kEnabled, in_process_stack_dumping,
3222 26783 : tracing_controller);
3223 : if (i::FLAG_verify_predictable) {
3224 : g_platform = new PredictablePlatform(std::unique_ptr<Platform>(g_platform));
3225 : }
3226 :
3227 26783 : v8::V8::InitializePlatform(g_platform);
3228 26783 : v8::V8::Initialize();
3229 26783 : if (options.natives_blob || options.snapshot_blob) {
3230 : v8::V8::InitializeExternalStartupData(options.natives_blob,
3231 0 : options.snapshot_blob);
3232 : } else {
3233 26783 : v8::V8::InitializeExternalStartupData(argv[0]);
3234 : }
3235 26783 : SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
3236 26783 : SetFlagsFromString("--redirect-code-traces-to=code.asm");
3237 : int result = 0;
3238 : Isolate::CreateParams create_params;
3239 : ShellArrayBufferAllocator shell_array_buffer_allocator;
3240 : MockArrayBufferAllocator mock_arraybuffer_allocator;
3241 26783 : if (options.mock_arraybuffer_allocator) {
3242 23 : Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
3243 : } else {
3244 26760 : Shell::array_buffer_allocator = &shell_array_buffer_allocator;
3245 : }
3246 26783 : create_params.array_buffer_allocator = Shell::array_buffer_allocator;
3247 : #ifdef ENABLE_VTUNE_JIT_INTERFACE
3248 : create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
3249 : #endif
3250 : create_params.constraints.ConfigureDefaults(
3251 26783 : base::SysInfo::AmountOfPhysicalMemory(),
3252 53566 : base::SysInfo::AmountOfVirtualMemory());
3253 :
3254 53566 : Shell::counter_map_ = new CounterMap();
3255 26783 : if (i::FLAG_dump_counters || i::FLAG_dump_counters_nvp || i::FLAG_gc_stats) {
3256 0 : create_params.counter_lookup_callback = LookupCounter;
3257 0 : create_params.create_histogram_callback = CreateHistogram;
3258 0 : create_params.add_histogram_sample_callback = AddHistogramSample;
3259 : }
3260 :
3261 26783 : if (i::trap_handler::UseTrapHandler()) {
3262 2655 : if (!v8::V8::RegisterDefaultSignalHandler()) {
3263 0 : fprintf(stderr, "Could not register signal handler");
3264 0 : exit(1);
3265 : }
3266 : }
3267 :
3268 26783 : Isolate* isolate = Isolate::New(create_params);
3269 : isolate->SetHostImportModuleDynamicallyCallback(
3270 26783 : Shell::HostImportModuleDynamically);
3271 : isolate->SetHostInitializeImportMetaObjectCallback(
3272 26783 : Shell::HostInitializeImportMetaObject);
3273 :
3274 26783 : D8Console console(isolate);
3275 : {
3276 : Isolate::Scope scope(isolate);
3277 26783 : Initialize(isolate);
3278 53566 : PerIsolateData data(isolate);
3279 26783 : debug::SetConsoleDelegate(isolate, &console);
3280 :
3281 26783 : if (options.trace_enabled) {
3282 : platform::tracing::TraceConfig* trace_config;
3283 0 : if (options.trace_config) {
3284 0 : int size = 0;
3285 0 : char* trace_config_json_str = ReadChars(options.trace_config, &size);
3286 : trace_config =
3287 0 : tracing::CreateTraceConfigFromJSON(isolate, trace_config_json_str);
3288 0 : delete[] trace_config_json_str;
3289 : } else {
3290 : trace_config =
3291 0 : platform::tracing::TraceConfig::CreateDefaultTraceConfig();
3292 : }
3293 0 : tracing_controller->StartTracing(trace_config);
3294 : }
3295 :
3296 26783 : if (options.stress_opt || options.stress_deopt) {
3297 : Testing::SetStressRunType(options.stress_opt
3298 : ? Testing::kStressTypeOpt
3299 4402 : : Testing::kStressTypeDeopt);
3300 4402 : options.stress_runs = Testing::GetStressRuns();
3301 30810 : for (int i = 0; i < options.stress_runs && result == 0; i++) {
3302 : printf("============ Stress %d/%d ============\n", i + 1,
3303 22006 : options.stress_runs);
3304 22006 : Testing::PrepareStressRun(i);
3305 22006 : bool last_run = i == options.stress_runs - 1;
3306 22006 : result = RunMain(isolate, argc, argv, last_run);
3307 : }
3308 : printf("======== Full Deoptimization =======\n");
3309 4402 : Testing::DeoptimizeAll(isolate);
3310 22381 : } else if (i::FLAG_stress_runs > 0) {
3311 30 : options.stress_runs = i::FLAG_stress_runs;
3312 190 : for (int i = 0; i < options.stress_runs && result == 0; i++) {
3313 : printf("============ Run %d/%d ============\n", i + 1,
3314 130 : options.stress_runs);
3315 130 : bool last_run = i == options.stress_runs - 1;
3316 130 : result = RunMain(isolate, argc, argv, last_run);
3317 : }
3318 : } else {
3319 : bool last_run = true;
3320 22351 : result = RunMain(isolate, argc, argv, last_run);
3321 : }
3322 :
3323 : // Run interactive shell if explicitly requested or if no script has been
3324 : // executed, but never on --test
3325 53566 : if (options.use_interactive_shell()) {
3326 0 : RunShell(isolate);
3327 : }
3328 :
3329 26788 : if (i::FLAG_trace_ignition_dispatches &&
3330 5 : i::FLAG_trace_ignition_dispatches_output_file != nullptr) {
3331 0 : WriteIgnitionDispatchCountersFile(isolate);
3332 : }
3333 :
3334 : // Shut down contexts and collect garbage.
3335 : evaluation_context_.Reset();
3336 : stringify_function_.Reset();
3337 26783 : CollectGarbage(isolate);
3338 : }
3339 26783 : OnExit(isolate);
3340 26783 : V8::Dispose();
3341 26783 : V8::ShutdownPlatform();
3342 26783 : delete g_platform;
3343 :
3344 26783 : return result;
3345 : }
3346 :
3347 : } // namespace v8
3348 :
3349 :
3350 : #ifndef GOOGLE3
3351 26783 : int main(int argc, char* argv[]) {
3352 26783 : return v8::Shell::Main(argc, argv);
3353 80349 : }
3354 : #endif
|