blob: 9466ab7d3a727c2fe12d70ac977df0b0cac57f35 [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Steve Blocka7e24c12009-10-30 11:49:00 +00004
5
Ben Murdochb8a8cc12014-11-26 15:28:44 +00006// Defined when linking against shared lib on Windows.
7#if defined(USING_V8_SHARED) && !defined(V8_SHARED)
Ben Murdoch69a99ed2011-11-30 16:03:39 +00008#define V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00009#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000010
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000011#include <errno.h>
12#include <stdlib.h>
13#include <string.h>
Ben Murdoch69a99ed2011-11-30 16:03:39 +000014#include <sys/stat.h>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000015
Ben Murdoch69a99ed2011-11-30 16:03:39 +000016#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000017#include <assert.h>
Ben Murdoch69a99ed2011-11-30 16:03:39 +000018#endif // V8_SHARED
Steve Block44f0eee2011-05-26 01:26:41 +010019
Ben Murdoch69a99ed2011-11-30 16:03:39 +000020#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +000021#include <algorithm>
Ben Murdochc5610432016-08-08 18:44:38 +010022#include <fstream>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000023#include <vector>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000024#endif // !V8_SHARED
25
26#ifdef V8_SHARED
27#include "include/v8-testing.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000028#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +000029
Ben Murdochb8a8cc12014-11-26 15:28:44 +000030#ifdef ENABLE_VTUNE_JIT_INTERFACE
31#include "src/third_party/vtune/v8-vtune.h"
32#endif
33
34#include "src/d8.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010035#include "src/ostreams.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000036
37#include "include/libplatform/libplatform.h"
38#ifndef V8_SHARED
39#include "src/api.h"
40#include "src/base/cpu.h"
41#include "src/base/logging.h"
42#include "src/base/platform/platform.h"
43#include "src/base/sys-info.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040044#include "src/basic-block-profiler.h"
Ben Murdochc5610432016-08-08 18:44:38 +010045#include "src/interpreter/interpreter.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000046#include "src/snapshot/natives.h"
47#include "src/utils.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000048#include "src/v8.h"
49#endif // !V8_SHARED
50
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000051#if !defined(_WIN32) && !defined(_WIN64)
52#include <unistd.h> // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000053#else
54#include <windows.h> // NOLINT
55#if defined(_MSC_VER)
56#include <crtdbg.h> // NOLINT
57#endif // defined(_MSC_VER)
58#endif // !defined(_WIN32) && !defined(_WIN64)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000059
Ben Murdochb8a8cc12014-11-26 15:28:44 +000060#ifndef DCHECK
61#define DCHECK(condition) assert(condition)
Ben Murdoch69a99ed2011-11-30 16:03:39 +000062#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000063
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000064#ifndef CHECK
65#define CHECK(condition) assert(condition)
66#endif
67
Steve Blocka7e24c12009-10-30 11:49:00 +000068namespace v8 {
69
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070namespace {
Steve Blocka7e24c12009-10-30 11:49:00 +000071
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000072const int MB = 1024 * 1024;
73#ifndef V8_SHARED
74const int kMaxWorkers = 50;
75#endif
76
77
78class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
79 public:
80 virtual void* Allocate(size_t length) {
81 void* data = AllocateUninitialized(length);
82 return data == NULL ? data : memset(data, 0, length);
83 }
84 virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
85 virtual void Free(void* data, size_t) { free(data); }
86};
87
88
89class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
90 public:
91 void* Allocate(size_t length) override {
92 size_t actual_length = length > 10 * MB ? 1 : length;
93 void* data = AllocateUninitialized(actual_length);
94 return data == NULL ? data : memset(data, 0, actual_length);
95 }
96 void* AllocateUninitialized(size_t length) override {
97 return length > 10 * MB ? malloc(1) : malloc(length);
98 }
99 void Free(void* p, size_t) override { free(p); }
100};
101
102
103#ifndef V8_SHARED
104// Predictable v8::Platform implementation. All background and foreground
105// tasks are run immediately, delayed tasks are not executed at all.
106class PredictablePlatform : public Platform {
107 public:
108 PredictablePlatform() {}
109
110 void CallOnBackgroundThread(Task* task,
111 ExpectedRuntime expected_runtime) override {
112 task->Run();
113 delete task;
114 }
115
116 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
117 task->Run();
118 delete task;
119 }
120
121 void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
122 double delay_in_seconds) override {
123 delete task;
124 }
125
126 void CallIdleOnForegroundThread(v8::Isolate* isolate,
127 IdleTask* task) override {
128 UNREACHABLE();
129 }
130
131 bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
132
133 double MonotonicallyIncreasingTime() override {
134 return synthetic_time_in_sec_ += 0.00001;
135 }
136
137 uint64_t AddTraceEvent(char phase, const uint8_t* categoryEnabledFlag,
Ben Murdochda12d292016-06-02 14:46:10 +0100138 const char* name, const char* scope, uint64_t id,
139 uint64_t bind_id, int numArgs, const char** argNames,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000140 const uint8_t* argTypes, const uint64_t* argValues,
141 unsigned int flags) override {
142 return 0;
143 }
144
145 void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
146 const char* name, uint64_t handle) override {}
147
148 const uint8_t* GetCategoryGroupEnabled(const char* name) override {
149 static uint8_t no = 0;
150 return &no;
151 }
152
153 const char* GetCategoryGroupName(
154 const uint8_t* categoryEnabledFlag) override {
155 static const char* dummy = "dummy";
156 return dummy;
157 }
158
159 private:
160 double synthetic_time_in_sec_ = 0.0;
161
162 DISALLOW_COPY_AND_ASSIGN(PredictablePlatform);
163};
164#endif // !V8_SHARED
165
166
167v8::Platform* g_platform = NULL;
168
169
170static Local<Value> Throw(Isolate* isolate, const char* message) {
171 return isolate->ThrowException(
172 String::NewFromUtf8(isolate, message, NewStringType::kNormal)
173 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000174}
175
176
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000177#ifndef V8_SHARED
178bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) {
179 for (int i = 0; i < list.length(); ++i) {
180 if (list[i]->StrictEquals(object)) {
181 return true;
182 }
183 }
184 return false;
185}
186
187
188Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
189 if (object->InternalFieldCount() != 1) {
190 Throw(isolate, "this is not a Worker");
191 return NULL;
192 }
193
194 Worker* worker =
195 static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
196 if (worker == NULL) {
197 Throw(isolate, "Worker is defunct because main thread is terminating");
198 return NULL;
199 }
200
201 return worker;
202}
203#endif // !V8_SHARED
204
205
206} // namespace
207
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000208
209class PerIsolateData {
210 public:
211 explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
212 HandleScope scope(isolate);
213 isolate->SetData(0, this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000214 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000215
216 ~PerIsolateData() {
217 isolate_->SetData(0, NULL); // Not really needed, just to be sure...
218 }
219
220 inline static PerIsolateData* Get(Isolate* isolate) {
221 return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
222 }
223
224 class RealmScope {
225 public:
226 explicit RealmScope(PerIsolateData* data);
227 ~RealmScope();
228 private:
229 PerIsolateData* data_;
230 };
231
232 private:
233 friend class Shell;
234 friend class RealmScope;
235 Isolate* isolate_;
236 int realm_count_;
237 int realm_current_;
238 int realm_switch_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 Global<Context>* realms_;
240 Global<Value> realm_shared_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000241
242 int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
243 int arg_offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000244 int RealmFind(Local<Context> context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000245};
246
247
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100248#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000249CounterMap* Shell::counter_map_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000250base::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000251CounterCollection Shell::local_counters_;
252CounterCollection* Shell::counters_ = &local_counters_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253base::LazyMutex Shell::context_mutex_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000254const base::TimeTicks Shell::kInitialTicks =
255 base::TimeTicks::HighResolutionNow();
Ben Murdochda12d292016-06-02 14:46:10 +0100256Global<Function> Shell::stringify_function_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000257base::LazyMutex Shell::workers_mutex_;
258bool Shell::allow_new_workers_ = true;
259i::List<Worker*> Shell::workers_;
260i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000261#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000262
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263Global<Context> Shell::evaluation_context_;
264ArrayBuffer::Allocator* Shell::array_buffer_allocator;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000265ShellOptions Shell::options;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000266base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
Steve Blocka7e24c12009-10-30 11:49:00 +0000267
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000268#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000269bool CounterMap::Match(void* key1, void* key2) {
270 const char* name1 = reinterpret_cast<const char*>(key1);
271 const char* name2 = reinterpret_cast<const char*>(key2);
272 return strcmp(name1, name2) == 0;
273}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000274#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000275
276
277// Converts a V8 value to a C string.
Steve Block6ded16b2010-05-10 14:33:55 +0100278const char* Shell::ToCString(const v8::String::Utf8Value& value) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000279 return *value ? *value : "<string conversion failed>";
280}
281
282
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400283ScriptCompiler::CachedData* CompileForCachedData(
284 Local<String> source, Local<Value> name,
285 ScriptCompiler::CompileOptions compile_options) {
286 int source_length = source->Length();
287 uint16_t* source_buffer = new uint16_t[source_length];
288 source->Write(source_buffer, 0, source_length);
289 int name_length = 0;
290 uint16_t* name_buffer = NULL;
291 if (name->IsString()) {
292 Local<String> name_string = Local<String>::Cast(name);
293 name_length = name_string->Length();
294 name_buffer = new uint16_t[name_length];
295 name_string->Write(name_buffer, 0, name_length);
296 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297 Isolate::CreateParams create_params;
298 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
299 Isolate* temp_isolate = Isolate::New(create_params);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400300 ScriptCompiler::CachedData* result = NULL;
301 {
302 Isolate::Scope isolate_scope(temp_isolate);
303 HandleScope handle_scope(temp_isolate);
304 Context::Scope context_scope(Context::New(temp_isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000305 Local<String> source_copy =
306 v8::String::NewFromTwoByte(temp_isolate, source_buffer,
307 v8::NewStringType::kNormal,
308 source_length).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400309 Local<Value> name_copy;
310 if (name_buffer) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000311 name_copy = v8::String::NewFromTwoByte(temp_isolate, name_buffer,
312 v8::NewStringType::kNormal,
313 name_length).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400314 } else {
315 name_copy = v8::Undefined(temp_isolate);
316 }
317 ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source,
319 compile_options).IsEmpty() &&
320 script_source.GetCachedData()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400321 int length = script_source.GetCachedData()->length;
322 uint8_t* cache = new uint8_t[length];
323 memcpy(cache, script_source.GetCachedData()->data, length);
324 result = new ScriptCompiler::CachedData(
325 cache, length, ScriptCompiler::CachedData::BufferOwned);
326 }
327 }
328 temp_isolate->Dispose();
329 delete[] source_buffer;
330 delete[] name_buffer;
331 return result;
332}
333
334
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335// Compile a string within the current v8 context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336MaybeLocal<Script> Shell::CompileString(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000337 Isolate* isolate, Local<String> source, Local<Value> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000338 ScriptCompiler::CompileOptions compile_options, SourceType source_type) {
339 Local<Context> context(isolate->GetCurrentContext());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000340 ScriptOrigin origin(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400341 if (compile_options == ScriptCompiler::kNoCompileOptions) {
342 ScriptCompiler::Source script_source(source, origin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 return source_type == SCRIPT
344 ? ScriptCompiler::Compile(context, &script_source,
345 compile_options)
346 : ScriptCompiler::CompileModule(context, &script_source,
347 compile_options);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000348 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400349
350 ScriptCompiler::CachedData* data =
351 CompileForCachedData(source, name, compile_options);
352 ScriptCompiler::Source cached_source(source, origin, data);
353 if (compile_options == ScriptCompiler::kProduceCodeCache) {
354 compile_options = ScriptCompiler::kConsumeCodeCache;
355 } else if (compile_options == ScriptCompiler::kProduceParserCache) {
356 compile_options = ScriptCompiler::kConsumeParserCache;
357 } else {
358 DCHECK(false); // A new compile option?
359 }
360 if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000361 MaybeLocal<Script> result =
362 source_type == SCRIPT
363 ? ScriptCompiler::Compile(context, &cached_source, compile_options)
364 : ScriptCompiler::CompileModule(context, &cached_source,
365 compile_options);
366 CHECK(data == NULL || !data->rejected);
367 return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000368}
369
370
Steve Blocka7e24c12009-10-30 11:49:00 +0000371// Executes a string within the current v8 context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000372bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
373 Local<Value> name, bool print_result,
374 bool report_exceptions, SourceType source_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000375 HandleScope handle_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000376 TryCatch try_catch(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100377 try_catch.SetVerbose(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000378
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000379 MaybeLocal<Value> maybe_result;
380 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000381 PerIsolateData* data = PerIsolateData::Get(isolate);
382 Local<Context> realm =
383 Local<Context>::New(isolate, data->realms_[data->realm_current_]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000384 Context::Scope context_scope(realm);
385 Local<Script> script;
386 if (!Shell::CompileString(isolate, source, name, options.compile_options,
387 source_type).ToLocal(&script)) {
388 // Print errors that happened during compilation.
389 if (report_exceptions) ReportException(isolate, &try_catch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000390 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000391 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000392 maybe_result = script->Run(realm);
393 EmptyMessageQueues(isolate);
394 data->realm_current_ = data->realm_switch_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000395 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000396 Local<Value> result;
397 if (!maybe_result.ToLocal(&result)) {
398 DCHECK(try_catch.HasCaught());
399 // Print errors that happened during execution.
400 if (report_exceptions) ReportException(isolate, &try_catch);
401 return false;
402 }
403 DCHECK(!try_catch.HasCaught());
404 if (print_result) {
405#if !defined(V8_SHARED)
406 if (options.test_shell) {
407#endif
408 if (!result->IsUndefined()) {
409 // If all went well and the result wasn't undefined then print
410 // the returned value.
411 v8::String::Utf8Value str(result);
412 fwrite(*str, sizeof(**str), str.length(), stdout);
413 printf("\n");
414 }
415#if !defined(V8_SHARED)
416 } else {
Ben Murdochda12d292016-06-02 14:46:10 +0100417 v8::String::Utf8Value str(Stringify(isolate, result));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 fwrite(*str, sizeof(**str), str.length(), stdout);
419 printf("\n");
420 }
421#endif
422 }
423 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000424}
425
426
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000427PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
428 data_->realm_count_ = 1;
429 data_->realm_current_ = 0;
430 data_->realm_switch_ = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000431 data_->realms_ = new Global<Context>[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000432 data_->realms_[0].Reset(data_->isolate_,
433 data_->isolate_->GetEnteredContext());
Steve Blocka7e24c12009-10-30 11:49:00 +0000434}
435
436
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000437PerIsolateData::RealmScope::~RealmScope() {
438 // Drop realms to avoid keeping them alive.
439 for (int i = 0; i < data_->realm_count_; ++i)
440 data_->realms_[i].Reset();
441 delete[] data_->realms_;
442 if (!data_->realm_shared_.IsEmpty())
443 data_->realm_shared_.Reset();
444}
445
446
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000447int PerIsolateData::RealmFind(Local<Context> context) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000448 for (int i = 0; i < realm_count_; ++i) {
449 if (realms_[i] == context) return i;
450 }
451 return -1;
452}
453
454
455int PerIsolateData::RealmIndexOrThrow(
456 const v8::FunctionCallbackInfo<v8::Value>& args,
457 int arg_offset) {
458 if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
459 Throw(args.GetIsolate(), "Invalid argument");
460 return -1;
461 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462 int index = args[arg_offset]
463 ->Int32Value(args.GetIsolate()->GetCurrentContext())
464 .FromMaybe(-1);
465 if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000466 Throw(args.GetIsolate(), "Invalid realm index");
467 return -1;
468 }
469 return index;
470}
471
472
473#ifndef V8_SHARED
474// performance.now() returns a time stamp as double, measured in milliseconds.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475// When FLAG_verify_predictable mode is enabled it returns result of
476// v8::Platform::MonotonicallyIncreasingTime().
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000477void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
478 if (i::FLAG_verify_predictable) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000480 } else {
481 base::TimeDelta delta =
482 base::TimeTicks::HighResolutionNow() - kInitialTicks;
483 args.GetReturnValue().Set(delta.InMillisecondsF());
484 }
485}
486#endif // !V8_SHARED
487
488
489// Realm.current() returns the index of the currently active realm.
490void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
491 Isolate* isolate = args.GetIsolate();
492 PerIsolateData* data = PerIsolateData::Get(isolate);
493 int index = data->RealmFind(isolate->GetEnteredContext());
494 if (index == -1) return;
495 args.GetReturnValue().Set(index);
496}
497
498
499// Realm.owner(o) returns the index of the realm that created o.
500void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
501 Isolate* isolate = args.GetIsolate();
502 PerIsolateData* data = PerIsolateData::Get(isolate);
503 if (args.Length() < 1 || !args[0]->IsObject()) {
504 Throw(args.GetIsolate(), "Invalid argument");
505 return;
506 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000507 int index = data->RealmFind(args[0]
508 ->ToObject(isolate->GetCurrentContext())
509 .ToLocalChecked()
510 ->CreationContext());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000511 if (index == -1) return;
512 args.GetReturnValue().Set(index);
513}
514
515
516// Realm.global(i) returns the global object of realm i.
517// (Note that properties of global objects cannot be read/written cross-realm.)
518void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
519 PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
520 int index = data->RealmIndexOrThrow(args, 0);
521 if (index == -1) return;
522 args.GetReturnValue().Set(
523 Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
524}
525
526
527// Realm.create() creates a new realm and returns its index.
528void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
529 Isolate* isolate = args.GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530 TryCatch try_catch(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 PerIsolateData* data = PerIsolateData::Get(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000532 Global<Context>* old_realms = data->realms_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000533 int index = data->realm_count_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000534 data->realms_ = new Global<Context>[++data->realm_count_];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000535 for (int i = 0; i < index; ++i) {
536 data->realms_[i].Reset(isolate, old_realms[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000537 old_realms[i].Reset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000538 }
539 delete[] old_realms;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000540 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
541 Local<Context> context = Context::New(isolate, NULL, global_template);
542 if (context.IsEmpty()) {
543 DCHECK(try_catch.HasCaught());
544 try_catch.ReThrow();
545 return;
546 }
547 data->realms_[index].Reset(isolate, context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 args.GetReturnValue().Set(index);
549}
550
551
552// Realm.dispose(i) disposes the reference to the realm i.
553void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
554 Isolate* isolate = args.GetIsolate();
555 PerIsolateData* data = PerIsolateData::Get(isolate);
556 int index = data->RealmIndexOrThrow(args, 0);
557 if (index == -1) return;
558 if (index == 0 ||
559 index == data->realm_current_ || index == data->realm_switch_) {
560 Throw(args.GetIsolate(), "Invalid realm index");
561 return;
562 }
563 data->realms_[index].Reset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000564 isolate->ContextDisposedNotification();
565 isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000566}
567
568
569// Realm.switch(i) switches to the realm i for consecutive interactive inputs.
570void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
571 Isolate* isolate = args.GetIsolate();
572 PerIsolateData* data = PerIsolateData::Get(isolate);
573 int index = data->RealmIndexOrThrow(args, 0);
574 if (index == -1) return;
575 data->realm_switch_ = index;
576}
577
578
579// Realm.eval(i, s) evaluates s in realm i and returns the result.
580void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
581 Isolate* isolate = args.GetIsolate();
582 PerIsolateData* data = PerIsolateData::Get(isolate);
583 int index = data->RealmIndexOrThrow(args, 0);
584 if (index == -1) return;
585 if (args.Length() < 2 || !args[1]->IsString()) {
586 Throw(args.GetIsolate(), "Invalid argument");
587 return;
588 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000589 ScriptCompiler::Source script_source(
590 args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
591 Local<UnboundScript> script;
592 if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
593 .ToLocal(&script)) {
594 return;
595 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000596 Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
597 realm->Enter();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000598 Local<Value> result;
599 if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
600 realm->Exit();
601 return;
602 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000603 realm->Exit();
604 args.GetReturnValue().Set(result);
605}
606
607
608// Realm.shared is an accessor for a single shared value across realms.
609void Shell::RealmSharedGet(Local<String> property,
610 const PropertyCallbackInfo<Value>& info) {
611 Isolate* isolate = info.GetIsolate();
612 PerIsolateData* data = PerIsolateData::Get(isolate);
613 if (data->realm_shared_.IsEmpty()) return;
614 info.GetReturnValue().Set(data->realm_shared_);
615}
616
617void Shell::RealmSharedSet(Local<String> property,
618 Local<Value> value,
619 const PropertyCallbackInfo<void>& info) {
620 Isolate* isolate = info.GetIsolate();
621 PerIsolateData* data = PerIsolateData::Get(isolate);
622 data->realm_shared_.Reset(isolate, value);
623}
624
625
626void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
627 Write(args);
628 printf("\n");
629 fflush(stdout);
630}
631
632
633void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000634 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000635 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000636 if (i != 0) {
637 printf(" ");
638 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000639
640 // Explicitly catch potential exceptions in toString().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000641 v8::TryCatch try_catch(args.GetIsolate());
642 Local<Value> arg = args[i];
643 Local<String> str_obj;
644
645 if (arg->IsSymbol()) {
646 arg = Local<Symbol>::Cast(arg)->Name();
647 }
648 if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
649 .ToLocal(&str_obj)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000650 try_catch.ReThrow();
651 return;
652 }
653
654 v8::String::Utf8Value str(str_obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000655 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
Steve Blockd0582a62009-12-15 09:54:21 +0000656 if (n != str.length()) {
657 printf("Error in fwrite\n");
Ben Murdoch589d6972011-11-30 16:04:58 +0000658 Exit(1);
Steve Blockd0582a62009-12-15 09:54:21 +0000659 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000660 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000661}
662
663
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000664void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000665 String::Utf8Value file(args[0]);
666 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667 Throw(args.GetIsolate(), "Error loading file");
668 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000669 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000670 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000671 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000672 Throw(args.GetIsolate(), "Error loading file");
673 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000674 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000675 args.GetReturnValue().Set(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000676}
677
678
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000679Local<String> Shell::ReadFromStdin(Isolate* isolate) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000680 static const int kBufferSize = 256;
681 char buffer[kBufferSize];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000682 Local<String> accumulator =
683 String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000684 int length;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000685 while (true) {
686 // Continue reading if the line ends with an escape '\\' or the line has
687 // not been fully read into the buffer yet (does not end with '\n').
688 // If fgets gets an error, just give up.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100689 char* input = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690 input = fgets(buffer, kBufferSize, stdin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000691 if (input == NULL) return Local<String>();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000692 length = static_cast<int>(strlen(buffer));
693 if (length == 0) {
694 return accumulator;
695 } else if (buffer[length-1] != '\n') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000696 accumulator = String::Concat(
697 accumulator,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000698 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
699 .ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000700 } else if (length > 1 && buffer[length-2] == '\\') {
701 buffer[length-2] = '\n';
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000702 accumulator = String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000703 accumulator,
704 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
705 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000706 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000707 return String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000708 accumulator,
709 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
710 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000711 }
712 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000713}
714
715
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000716void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000717 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000719 String::Utf8Value file(args[i]);
720 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000721 Throw(args.GetIsolate(), "Error loading file");
722 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000723 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000725 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000726 Throw(args.GetIsolate(), "Error loading file");
727 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000728 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000729 if (!ExecuteString(
730 args.GetIsolate(), source,
731 String::NewFromUtf8(args.GetIsolate(), *file,
732 NewStringType::kNormal).ToLocalChecked(),
733 false, true)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000734 Throw(args.GetIsolate(), "Error executing file");
735 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000736 }
737 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100738}
739
740
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000741#ifndef V8_SHARED
742void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
743 Isolate* isolate = args.GetIsolate();
744 HandleScope handle_scope(isolate);
745 if (args.Length() < 1 || !args[0]->IsString()) {
746 Throw(args.GetIsolate(), "1st argument must be string");
747 return;
748 }
749
750 if (!args.IsConstructCall()) {
751 Throw(args.GetIsolate(), "Worker must be constructed with new");
752 return;
753 }
754
755 {
756 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
757 if (workers_.length() >= kMaxWorkers) {
758 Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
759 return;
760 }
761
762 // Initialize the internal field to NULL; if we return early without
763 // creating a new Worker (because the main thread is terminating) we can
764 // early-out from the instance calls.
765 args.Holder()->SetAlignedPointerInInternalField(0, NULL);
766
767 if (!allow_new_workers_) return;
768
769 Worker* worker = new Worker;
770 args.Holder()->SetAlignedPointerInInternalField(0, worker);
771 workers_.Add(worker);
772
773 String::Utf8Value script(args[0]);
774 if (!*script) {
775 Throw(args.GetIsolate(), "Can't get worker script");
776 return;
777 }
778 worker->StartExecuteInThread(*script);
779 }
780}
781
782
783void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
784 Isolate* isolate = args.GetIsolate();
785 HandleScope handle_scope(isolate);
786 Local<Context> context = isolate->GetCurrentContext();
787
788 if (args.Length() < 1) {
789 Throw(isolate, "Invalid argument");
790 return;
791 }
792
793 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
794 if (!worker) {
795 return;
796 }
797
798 Local<Value> message = args[0];
799 ObjectList to_transfer;
800 if (args.Length() >= 2) {
801 if (!args[1]->IsArray()) {
802 Throw(isolate, "Transfer list must be an Array");
803 return;
804 }
805
806 Local<Array> transfer = Local<Array>::Cast(args[1]);
807 uint32_t length = transfer->Length();
808 for (uint32_t i = 0; i < length; ++i) {
809 Local<Value> element;
810 if (transfer->Get(context, i).ToLocal(&element)) {
811 if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) {
812 Throw(isolate,
813 "Transfer array elements must be an ArrayBuffer or "
814 "SharedArrayBuffer.");
815 break;
816 }
817
818 to_transfer.Add(Local<Object>::Cast(element));
819 }
820 }
821 }
822
823 ObjectList seen_objects;
824 SerializationData* data = new SerializationData;
825 if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) {
826 worker->PostMessage(data);
827 } else {
828 delete data;
829 }
830}
831
832
833void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
834 Isolate* isolate = args.GetIsolate();
835 HandleScope handle_scope(isolate);
836 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
837 if (!worker) {
838 return;
839 }
840
841 SerializationData* data = worker->GetMessage();
842 if (data) {
843 int offset = 0;
844 Local<Value> data_value;
845 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
846 args.GetReturnValue().Set(data_value);
847 }
848 delete data;
849 }
850}
851
852
853void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
854 Isolate* isolate = args.GetIsolate();
855 HandleScope handle_scope(isolate);
856 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
857 if (!worker) {
858 return;
859 }
860
861 worker->Terminate();
862}
863#endif // !V8_SHARED
864
865
866void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
867 int exit_code = (*args)[0]
868 ->Int32Value(args->GetIsolate()->GetCurrentContext())
869 .FromMaybe(0);
870#ifndef V8_SHARED
871 CleanupWorkers();
872#endif // !V8_SHARED
873 OnExit(args->GetIsolate());
874 Exit(exit_code);
875}
876
877
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000878void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000879 base::CallOnce(&quit_once_, &QuitOnce,
880 const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
Steve Blocka7e24c12009-10-30 11:49:00 +0000881}
882
883
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000884void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
885 args.GetReturnValue().Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000886 String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
887 NewStringType::kNormal).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000888}
889
890
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000891void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
892 HandleScope handle_scope(isolate);
893#ifndef V8_SHARED
Ben Murdochda12d292016-06-02 14:46:10 +0100894 Local<Context> context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000895 bool enter_context = !isolate->InContext();
896 if (enter_context) {
Ben Murdochda12d292016-06-02 14:46:10 +0100897 context = Local<Context>::New(isolate, evaluation_context_);
898 context->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000899 }
900#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000901 v8::String::Utf8Value exception(try_catch->Exception());
902 const char* exception_string = ToCString(exception);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 Local<Message> message = try_catch->Message();
Steve Blocka7e24c12009-10-30 11:49:00 +0000904 if (message.IsEmpty()) {
905 // V8 didn't provide any extra information about this error; just
906 // print the exception.
907 printf("%s\n", exception_string);
908 } else {
909 // Print (filename):(line number): (message).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000910 v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
Steve Blocka7e24c12009-10-30 11:49:00 +0000911 const char* filename_string = ToCString(filename);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000912 int linenum =
913 message->GetLineNumber(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000914 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
915 // Print line of source code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000916 v8::String::Utf8Value sourceline(
917 message->GetSourceLine(isolate->GetCurrentContext()).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000918 const char* sourceline_string = ToCString(sourceline);
919 printf("%s\n", sourceline_string);
920 // Print wavy underline (GetUnderline is deprecated).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000921 int start =
922 message->GetStartColumn(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000923 for (int i = 0; i < start; i++) {
924 printf(" ");
925 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000926 int end = message->GetEndColumn(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000927 for (int i = start; i < end; i++) {
928 printf("^");
929 }
930 printf("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931 Local<Value> stack_trace_string;
932 if (try_catch->StackTrace(isolate->GetCurrentContext())
933 .ToLocal(&stack_trace_string) &&
934 stack_trace_string->IsString()) {
935 v8::String::Utf8Value stack_trace(
936 Local<String>::Cast(stack_trace_string));
937 printf("%s\n", ToCString(stack_trace));
Ben Murdoch257744e2011-11-30 15:57:28 +0000938 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000939 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000940 printf("\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000941#ifndef V8_SHARED
Ben Murdochda12d292016-06-02 14:46:10 +0100942 if (enter_context) context->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000943#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000944}
945
946
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000947#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000948int32_t* Counter::Bind(const char* name, bool is_histogram) {
949 int i;
950 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
951 name_[i] = static_cast<char>(name[i]);
952 name_[i] = '\0';
953 is_histogram_ = is_histogram;
954 return ptr();
955}
956
957
958void Counter::AddSample(int32_t sample) {
959 count_++;
960 sample_total_ += sample;
961}
962
963
964CounterCollection::CounterCollection() {
965 magic_number_ = 0xDEADFACE;
966 max_counters_ = kMaxCounters;
967 max_name_size_ = Counter::kMaxNameSize;
968 counters_in_use_ = 0;
969}
970
971
972Counter* CounterCollection::GetNextCounter() {
973 if (counters_in_use_ == kMaxCounters) return NULL;
974 return &counters_[counters_in_use_++];
975}
976
977
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000978void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
979 counters_file_ = base::OS::MemoryMappedFile::create(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000980 name, sizeof(CounterCollection), &local_counters_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000981 void* memory = (counters_file_ == NULL) ?
982 NULL : counters_file_->memory();
983 if (memory == NULL) {
984 printf("Could not map counters file %s\n", name);
Ben Murdoch589d6972011-11-30 16:04:58 +0000985 Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000986 }
987 counters_ = static_cast<CounterCollection*>(memory);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000988 isolate->SetCounterFunction(LookupCounter);
989 isolate->SetCreateHistogramFunction(CreateHistogram);
990 isolate->SetAddHistogramSampleFunction(AddHistogramSample);
Steve Blocka7e24c12009-10-30 11:49:00 +0000991}
992
993
994int CounterMap::Hash(const char* name) {
995 int h = 0;
996 int c;
997 while ((c = *name++) != 0) {
998 h += h << 5;
999 h += c;
1000 }
1001 return h;
1002}
1003
1004
1005Counter* Shell::GetCounter(const char* name, bool is_histogram) {
1006 Counter* counter = counter_map_->Lookup(name);
1007
1008 if (counter == NULL) {
1009 counter = counters_->GetNextCounter();
1010 if (counter != NULL) {
1011 counter_map_->Set(name, counter);
1012 counter->Bind(name, is_histogram);
1013 }
1014 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001015 DCHECK(counter->is_histogram() == is_histogram);
Steve Blocka7e24c12009-10-30 11:49:00 +00001016 }
1017 return counter;
1018}
1019
1020
1021int* Shell::LookupCounter(const char* name) {
1022 Counter* counter = GetCounter(name, false);
1023
1024 if (counter != NULL) {
1025 return counter->ptr();
1026 } else {
1027 return NULL;
1028 }
1029}
1030
1031
1032void* Shell::CreateHistogram(const char* name,
1033 int min,
1034 int max,
1035 size_t buckets) {
1036 return GetCounter(name, true);
1037}
1038
1039
1040void Shell::AddHistogramSample(void* histogram, int sample) {
1041 Counter* counter = reinterpret_cast<Counter*>(histogram);
1042 counter->AddSample(sample);
1043}
1044
Ben Murdochda12d292016-06-02 14:46:10 +01001045// Turn a value into a human-readable string.
1046Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
1047 v8::Local<v8::Context> context =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001048 v8::Local<v8::Context>::New(isolate, evaluation_context_);
Ben Murdochda12d292016-06-02 14:46:10 +01001049 if (stringify_function_.IsEmpty()) {
1050 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
1051 i::Vector<const char> source_string =
1052 i::NativesCollection<i::D8>::GetScriptSource(source_index);
1053 i::Vector<const char> source_name =
1054 i::NativesCollection<i::D8>::GetScriptName(source_index);
1055 Local<String> source =
1056 String::NewFromUtf8(isolate, source_string.start(),
1057 NewStringType::kNormal, source_string.length())
1058 .ToLocalChecked();
1059 Local<String> name =
1060 String::NewFromUtf8(isolate, source_name.start(),
1061 NewStringType::kNormal, source_name.length())
1062 .ToLocalChecked();
1063 ScriptOrigin origin(name);
1064 Local<Script> script =
1065 Script::Compile(context, source, &origin).ToLocalChecked();
1066 stringify_function_.Reset(
1067 isolate, script->Run(context).ToLocalChecked().As<Function>());
1068 }
1069 Local<Function> fun = Local<Function>::New(isolate, stringify_function_);
1070 Local<Value> argv[1] = {value};
1071 v8::TryCatch try_catch(isolate);
1072 MaybeLocal<Value> result =
1073 fun->Call(context, Undefined(isolate), 1, argv).ToLocalChecked();
1074 if (result.IsEmpty()) return String::Empty(isolate);
1075 return result.ToLocalChecked().As<String>();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001076}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001078
1079
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001080Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
1081 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
1082 global_template->Set(
1083 String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
1084 .ToLocalChecked(),
1085 FunctionTemplate::New(isolate, Print));
1086 global_template->Set(
1087 String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
1088 .ToLocalChecked(),
1089 FunctionTemplate::New(isolate, Write));
1090 global_template->Set(
1091 String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
1092 .ToLocalChecked(),
1093 FunctionTemplate::New(isolate, Read));
1094 global_template->Set(
1095 String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
1096 .ToLocalChecked(),
1097 FunctionTemplate::New(isolate, ReadBuffer));
1098 global_template->Set(
1099 String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
1100 .ToLocalChecked(),
1101 FunctionTemplate::New(isolate, ReadLine));
1102 global_template->Set(
1103 String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
1104 .ToLocalChecked(),
1105 FunctionTemplate::New(isolate, Load));
1106 // Some Emscripten-generated code tries to call 'quit', which in turn would
1107 // call C's exit(). This would lead to memory leaks, because there is no way
1108 // we can terminate cleanly then, so we need a way to hide 'quit'.
1109 if (!options.omit_quit) {
1110 global_template->Set(
1111 String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
1112 .ToLocalChecked(),
1113 FunctionTemplate::New(isolate, Quit));
1114 }
1115 global_template->Set(
1116 String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
1117 .ToLocalChecked(),
1118 FunctionTemplate::New(isolate, Version));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001119
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001120 // Bind the Realm object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001121 Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
1122 realm_template->Set(
1123 String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
1124 .ToLocalChecked(),
1125 FunctionTemplate::New(isolate, RealmCurrent));
1126 realm_template->Set(
1127 String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
1128 .ToLocalChecked(),
1129 FunctionTemplate::New(isolate, RealmOwner));
1130 realm_template->Set(
1131 String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1132 .ToLocalChecked(),
1133 FunctionTemplate::New(isolate, RealmGlobal));
1134 realm_template->Set(
1135 String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
1136 .ToLocalChecked(),
1137 FunctionTemplate::New(isolate, RealmCreate));
1138 realm_template->Set(
1139 String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
1140 .ToLocalChecked(),
1141 FunctionTemplate::New(isolate, RealmDispose));
1142 realm_template->Set(
1143 String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
1144 .ToLocalChecked(),
1145 FunctionTemplate::New(isolate, RealmSwitch));
1146 realm_template->Set(
1147 String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
1148 .ToLocalChecked(),
1149 FunctionTemplate::New(isolate, RealmEval));
1150 realm_template->SetAccessor(
1151 String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
1152 .ToLocalChecked(),
1153 RealmSharedGet, RealmSharedSet);
1154 global_template->Set(
1155 String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
1156 .ToLocalChecked(),
1157 realm_template);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001158
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001159#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001160 Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
1161 performance_template->Set(
1162 String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
1163 .ToLocalChecked(),
1164 FunctionTemplate::New(isolate, PerformanceNow));
1165 global_template->Set(
1166 String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
1167 .ToLocalChecked(),
1168 performance_template);
1169
1170 Local<FunctionTemplate> worker_fun_template =
1171 FunctionTemplate::New(isolate, WorkerNew);
1172 Local<Signature> worker_signature =
1173 Signature::New(isolate, worker_fun_template);
1174 worker_fun_template->SetClassName(
1175 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1176 .ToLocalChecked());
1177 worker_fun_template->ReadOnlyPrototype();
1178 worker_fun_template->PrototypeTemplate()->Set(
1179 String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
1180 .ToLocalChecked(),
1181 FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
1182 worker_signature));
1183 worker_fun_template->PrototypeTemplate()->Set(
1184 String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
1185 .ToLocalChecked(),
1186 FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
1187 worker_signature));
1188 worker_fun_template->PrototypeTemplate()->Set(
1189 String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
1190 .ToLocalChecked(),
1191 FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
1192 worker_signature));
1193 worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
1194 global_template->Set(
1195 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1196 .ToLocalChecked(),
1197 worker_fun_template);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001198#endif // !V8_SHARED
1199
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001200 Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001201 AddOSMethods(isolate, os_templ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001202 global_template->Set(
1203 String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
1204 .ToLocalChecked(),
1205 os_templ);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001206
1207 return global_template;
Steve Blocka7e24c12009-10-30 11:49:00 +00001208}
1209
Ben Murdoch097c5b22016-05-18 11:27:45 +01001210static void EmptyMessageCallback(Local<Message> message, Local<Value> error) {
1211 // Nothing to be done here, exceptions thrown up to the shell will be reported
1212 // separately by {Shell::ReportException} after they are caught.
1213}
Steve Blocka7e24c12009-10-30 11:49:00 +00001214
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001215void Shell::Initialize(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001216#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001217 // Set up counters
1218 if (i::StrLength(i::FLAG_map_counters) != 0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001219 MapCounters(isolate, i::FLAG_map_counters);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001220#endif // !V8_SHARED
Ben Murdoch097c5b22016-05-18 11:27:45 +01001221 // Disable default message reporting.
1222 isolate->AddMessageListener(EmptyMessageCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001223}
1224
1225
1226Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001227#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001228 // This needs to be a critical section since this is not thread-safe
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001229 base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001230#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001231 // Initialize the global objects
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001232 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001233 EscapableHandleScope handle_scope(isolate);
1234 Local<Context> context = Context::New(isolate, NULL, global_template);
1235 DCHECK(!context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001236 Context::Scope scope(context);
1237
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001238#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001239 i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001240 i::JSArguments js_args = i::FLAG_js_arguments;
1241 i::Handle<i::FixedArray> arguments_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001242 factory->NewFixedArray(js_args.argc);
1243 for (int j = 0; j < js_args.argc; j++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001244 i::Handle<i::String> arg =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001245 factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001246 arguments_array->set(j, *arg);
1247 }
1248 i::Handle<i::JSArray> arguments_jsarray =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001249 factory->NewJSArrayWithElements(arguments_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001250 context->Global()
1251 ->Set(context,
1252 String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
1253 .ToLocalChecked(),
1254 Utils::ToLocal(arguments_jsarray))
1255 .FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001256#endif // !V8_SHARED
1257 return handle_scope.Escape(context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001258}
1259
1260
Ben Murdoch589d6972011-11-30 16:04:58 +00001261void Shell::Exit(int exit_code) {
1262 // Use _exit instead of exit to avoid races between isolate
1263 // threads and static destructors.
1264 fflush(stdout);
1265 fflush(stderr);
1266 _exit(exit_code);
1267}
1268
1269
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001270#ifndef V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001271struct CounterAndKey {
1272 Counter* counter;
1273 const char* key;
1274};
1275
1276
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001277inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
1278 return strcmp(lhs.key, rhs.key) < 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001279}
Ben Murdochc5610432016-08-08 18:44:38 +01001280
1281void Shell::WriteIgnitionDispatchCountersFile(v8::Isolate* isolate) {
1282 HandleScope handle_scope(isolate);
1283 Local<Context> context = Context::New(isolate);
1284 Context::Scope context_scope(context);
1285
1286 Local<Object> dispatch_counters = reinterpret_cast<i::Isolate*>(isolate)
1287 ->interpreter()
1288 ->GetDispatchCountersObject();
1289 std::ofstream dispatch_counters_stream(
1290 i::FLAG_trace_ignition_dispatches_output_file);
1291 dispatch_counters_stream << *String::Utf8Value(
1292 JSON::Stringify(context, dispatch_counters).ToLocalChecked());
1293}
1294
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001295#endif // !V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001296
1297
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001298void Shell::OnExit(v8::Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001299#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001300 if (i::FLAG_dump_counters) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001301 int number_of_counters = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001302 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001303 number_of_counters++;
1304 }
1305 CounterAndKey* counters = new CounterAndKey[number_of_counters];
1306 int j = 0;
1307 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
1308 counters[j].counter = i.CurrentValue();
1309 counters[j].key = i.CurrentKey();
1310 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001311 std::sort(counters, counters + number_of_counters);
1312 printf("+----------------------------------------------------------------+"
1313 "-------------+\n");
1314 printf("| Name |"
1315 " Value |\n");
1316 printf("+----------------------------------------------------------------+"
1317 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001318 for (j = 0; j < number_of_counters; j++) {
1319 Counter* counter = counters[j].counter;
1320 const char* key = counters[j].key;
Steve Blocka7e24c12009-10-30 11:49:00 +00001321 if (counter->is_histogram()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001322 printf("| c:%-60s | %11i |\n", key, counter->count());
1323 printf("| t:%-60s | %11i |\n", key, counter->sample_total());
Steve Blocka7e24c12009-10-30 11:49:00 +00001324 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001325 printf("| %-62s | %11i |\n", key, counter->count());
Steve Blocka7e24c12009-10-30 11:49:00 +00001326 }
1327 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001328 printf("+----------------------------------------------------------------+"
1329 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001330 delete [] counters;
Steve Blocka7e24c12009-10-30 11:49:00 +00001331 }
Ben Murdochc5610432016-08-08 18:44:38 +01001332
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001333 delete counters_file_;
1334 delete counter_map_;
1335#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001336}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001337
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001338
1339
1340static FILE* FOpen(const char* path, const char* mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001341#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001342 FILE* result;
1343 if (fopen_s(&result, path, mode) == 0) {
1344 return result;
1345 } else {
1346 return NULL;
1347 }
1348#else
1349 FILE* file = fopen(path, mode);
1350 if (file == NULL) return NULL;
1351 struct stat file_stat;
1352 if (fstat(fileno(file), &file_stat) != 0) return NULL;
1353 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
1354 if (is_regular_file) return file;
1355 fclose(file);
1356 return NULL;
1357#endif
1358}
Steve Blocka7e24c12009-10-30 11:49:00 +00001359
1360
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001362 FILE* file = FOpen(name, "rb");
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 if (file == NULL) return NULL;
1364
1365 fseek(file, 0, SEEK_END);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001366 size_t size = ftell(file);
Steve Blocka7e24c12009-10-30 11:49:00 +00001367 rewind(file);
1368
1369 char* chars = new char[size + 1];
1370 chars[size] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001371 for (size_t i = 0; i < size;) {
1372 i += fread(&chars[i], 1, size - i, file);
1373 if (ferror(file)) {
1374 fclose(file);
1375 delete[] chars;
1376 return nullptr;
1377 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001378 }
1379 fclose(file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001380 *size_out = static_cast<int>(size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 return chars;
1382}
1383
1384
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001385struct DataAndPersistent {
1386 uint8_t* data;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001387 int byte_length;
1388 Global<ArrayBuffer> handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001389};
1390
1391
1392static void ReadBufferWeakCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001393 const v8::WeakCallbackInfo<DataAndPersistent>& data) {
1394 int byte_length = data.GetParameter()->byte_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
1396 -static_cast<intptr_t>(byte_length));
1397
1398 delete[] data.GetParameter()->data;
1399 data.GetParameter()->handle.Reset();
1400 delete data.GetParameter();
1401}
1402
1403
1404void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
1405 DCHECK(sizeof(char) == sizeof(uint8_t)); // NOLINT
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001406 String::Utf8Value filename(args[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001407 int length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001408 if (*filename == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409 Throw(args.GetIsolate(), "Error loading file");
1410 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001411 }
1412
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413 Isolate* isolate = args.GetIsolate();
1414 DataAndPersistent* data = new DataAndPersistent;
1415 data->data = reinterpret_cast<uint8_t*>(
1416 ReadChars(args.GetIsolate(), *filename, &length));
1417 if (data->data == NULL) {
1418 delete data;
1419 Throw(args.GetIsolate(), "Error reading file");
1420 return;
1421 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001422 data->byte_length = length;
1423 Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001424 data->handle.Reset(isolate, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001425 data->handle.SetWeak(data, ReadBufferWeakCallback,
1426 v8::WeakCallbackType::kParameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001427 data->handle.MarkIndependent();
1428 isolate->AdjustAmountOfExternalAllocatedMemory(length);
1429
1430 args.GetReturnValue().Set(buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00001431}
1432
1433
Steve Blocka7e24c12009-10-30 11:49:00 +00001434// Reads a file into a v8 string.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001436 int size = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001437 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001438 if (chars == NULL) return Local<String>();
1439 Local<String> result =
1440 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1441 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001442 delete[] chars;
1443 return result;
1444}
1445
1446
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447void Shell::RunShell(Isolate* isolate) {
1448 HandleScope outer_scope(isolate);
1449 v8::Local<v8::Context> context =
1450 v8::Local<v8::Context>::New(isolate, evaluation_context_);
1451 v8::Context::Scope context_scope(context);
1452 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001453 Local<String> name =
1454 String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
1455 .ToLocalChecked();
1456 printf("V8 version %s\n", V8::GetVersion());
Steve Blocka7e24c12009-10-30 11:49:00 +00001457 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001458 HandleScope inner_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001459 printf("d8> ");
1460#if defined(__native_client__)
1461 // Native Client libc is used to being embedded in Chrome and
1462 // has trouble recognizing when to flush.
1463 fflush(stdout);
1464#endif
1465 Local<String> input = Shell::ReadFromStdin(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001466 if (input.IsEmpty()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001467 ExecuteString(isolate, input, name, true, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001468 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001469 printf("\n");
1470}
1471
1472
Ben Murdoch589d6972011-11-30 16:04:58 +00001473SourceGroup::~SourceGroup() {
1474#ifndef V8_SHARED
Ben Murdoch589d6972011-11-30 16:04:58 +00001475 delete thread_;
1476 thread_ = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001477#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001478}
Steve Blocka7e24c12009-10-30 11:49:00 +00001479
Steve Blocka7e24c12009-10-30 11:49:00 +00001480
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001481void SourceGroup::Execute(Isolate* isolate) {
1482 bool exception_was_thrown = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001483 for (int i = begin_offset_; i < end_offset_; ++i) {
1484 const char* arg = argv_[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001485 Shell::SourceType source_type = Shell::SCRIPT;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001486 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1487 // Execute argument given to -e option directly.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001488 HandleScope handle_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001489 Local<String> file_name =
1490 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1491 .ToLocalChecked();
1492 Local<String> source =
1493 String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
1494 .ToLocalChecked();
1495 Shell::options.script_executed = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001496 if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1497 exception_was_thrown = true;
1498 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001499 }
1500 ++i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001501 continue;
1502 } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
1503 // Treat the next file as a module.
1504 source_type = Shell::MODULE;
1505 arg = argv_[++i];
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001506 } else if (arg[0] == '-') {
1507 // Ignore other options. They have been parsed already.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 continue;
1509 }
1510
1511 // Use all other arguments as names of files to load and run.
1512 HandleScope handle_scope(isolate);
1513 Local<String> file_name =
1514 String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
1515 .ToLocalChecked();
1516 Local<String> source = ReadFile(isolate, arg);
1517 if (source.IsEmpty()) {
1518 printf("Error reading '%s'\n", arg);
1519 Shell::Exit(1);
1520 }
1521 Shell::options.script_executed = true;
1522 if (!Shell::ExecuteString(isolate, source, file_name, false, true,
1523 source_type)) {
1524 exception_was_thrown = true;
1525 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001526 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001527 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001528 if (exception_was_thrown != Shell::options.expected_to_throw) {
1529 Shell::Exit(1);
1530 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001531}
Steve Blocka7e24c12009-10-30 11:49:00 +00001532
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001533
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001534Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001535 int size;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001536 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001537 if (chars == NULL) return Local<String>();
1538 Local<String> result =
1539 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1540 .ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001541 delete[] chars;
1542 return result;
1543}
1544
1545
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001546#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001547base::Thread::Options SourceGroup::GetThreadOptions() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001548 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1549 // which is not enough to parse the big literal expressions used in tests.
1550 // The stack size should be at least StackGuard::kLimitSize + some
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001551 // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001552 return base::Thread::Options("IsolateThread", 2 * MB);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001553}
1554
1555
1556void SourceGroup::ExecuteInThread() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001557 Isolate::CreateParams create_params;
1558 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1559 Isolate* isolate = Isolate::New(create_params);
1560 for (int i = 0; i < Shell::options.stress_runs; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001561 next_semaphore_.Wait();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001562 {
1563 Isolate::Scope iscope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001564 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001565 HandleScope scope(isolate);
1566 PerIsolateData data(isolate);
1567 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1568 {
1569 Context::Scope cscope(context);
1570 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1571 Execute(isolate);
1572 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001573 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001574 Shell::CollectGarbage(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001575 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001576 done_semaphore_.Signal();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001577 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001578
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001579 isolate->Dispose();
1580}
1581
1582
1583void SourceGroup::StartExecuteInThread() {
1584 if (thread_ == NULL) {
1585 thread_ = new IsolateThread(this);
1586 thread_->Start();
1587 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001588 next_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001589}
1590
1591
1592void SourceGroup::WaitForThread() {
1593 if (thread_ == NULL) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001594 done_semaphore_.Wait();
1595}
1596
1597
1598void SourceGroup::JoinThread() {
1599 if (thread_ == NULL) return;
1600 thread_->Join();
1601}
1602
1603
1604SerializationData::~SerializationData() {
1605 // Any ArrayBuffer::Contents are owned by this SerializationData object if
1606 // ownership hasn't been transferred out via ReadArrayBufferContents.
1607 // SharedArrayBuffer::Contents may be used by multiple threads, so must be
1608 // cleaned up by the main thread in Shell::CleanupWorkers().
1609 for (int i = 0; i < array_buffer_contents_.length(); ++i) {
1610 ArrayBuffer::Contents& contents = array_buffer_contents_[i];
1611 if (contents.Data()) {
1612 Shell::array_buffer_allocator->Free(contents.Data(),
1613 contents.ByteLength());
1614 }
1615 }
1616}
1617
1618
1619void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); }
1620
1621
1622void SerializationData::WriteMemory(const void* p, int length) {
1623 if (length > 0) {
1624 i::Vector<uint8_t> block = data_.AddBlock(0, length);
1625 memcpy(&block[0], p, length);
1626 }
1627}
1628
1629
1630void SerializationData::WriteArrayBufferContents(
1631 const ArrayBuffer::Contents& contents) {
1632 array_buffer_contents_.Add(contents);
1633 WriteTag(kSerializationTagTransferredArrayBuffer);
1634 int index = array_buffer_contents_.length() - 1;
1635 Write(index);
1636}
1637
1638
1639void SerializationData::WriteSharedArrayBufferContents(
1640 const SharedArrayBuffer::Contents& contents) {
1641 shared_array_buffer_contents_.Add(contents);
1642 WriteTag(kSerializationTagTransferredSharedArrayBuffer);
1643 int index = shared_array_buffer_contents_.length() - 1;
1644 Write(index);
1645}
1646
1647
1648SerializationTag SerializationData::ReadTag(int* offset) const {
1649 return static_cast<SerializationTag>(Read<uint8_t>(offset));
1650}
1651
1652
1653void SerializationData::ReadMemory(void* p, int length, int* offset) const {
1654 if (length > 0) {
1655 memcpy(p, &data_[*offset], length);
1656 (*offset) += length;
1657 }
1658}
1659
1660
1661void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents,
1662 int* offset) const {
1663 int index = Read<int>(offset);
1664 DCHECK(index < array_buffer_contents_.length());
1665 *contents = array_buffer_contents_[index];
1666 // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter
1667 // our copy so it won't be double-free'd when this SerializationData is
1668 // destroyed.
1669 array_buffer_contents_[index] = ArrayBuffer::Contents();
1670}
1671
1672
1673void SerializationData::ReadSharedArrayBufferContents(
1674 SharedArrayBuffer::Contents* contents, int* offset) const {
1675 int index = Read<int>(offset);
1676 DCHECK(index < shared_array_buffer_contents_.length());
1677 *contents = shared_array_buffer_contents_[index];
1678}
1679
1680
1681void SerializationDataQueue::Enqueue(SerializationData* data) {
1682 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1683 data_.Add(data);
1684}
1685
1686
1687bool SerializationDataQueue::Dequeue(SerializationData** data) {
1688 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1689 *data = NULL;
1690 if (data_.is_empty()) return false;
1691 *data = data_.Remove(0);
1692 return true;
1693}
1694
1695
1696bool SerializationDataQueue::IsEmpty() {
1697 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1698 return data_.is_empty();
1699}
1700
1701
1702void SerializationDataQueue::Clear() {
1703 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1704 for (int i = 0; i < data_.length(); ++i) {
1705 delete data_[i];
1706 }
1707 data_.Clear();
1708}
1709
1710
1711Worker::Worker()
1712 : in_semaphore_(0),
1713 out_semaphore_(0),
1714 thread_(NULL),
1715 script_(NULL),
1716 running_(false) {}
1717
1718
1719Worker::~Worker() {
1720 delete thread_;
1721 thread_ = NULL;
1722 delete[] script_;
1723 script_ = NULL;
1724 in_queue_.Clear();
1725 out_queue_.Clear();
1726}
1727
1728
1729void Worker::StartExecuteInThread(const char* script) {
1730 running_ = true;
1731 script_ = i::StrDup(script);
1732 thread_ = new WorkerThread(this);
1733 thread_->Start();
1734}
1735
1736
1737void Worker::PostMessage(SerializationData* data) {
1738 in_queue_.Enqueue(data);
1739 in_semaphore_.Signal();
1740}
1741
1742
1743SerializationData* Worker::GetMessage() {
1744 SerializationData* data = NULL;
1745 while (!out_queue_.Dequeue(&data)) {
1746 // If the worker is no longer running, and there are no messages in the
1747 // queue, don't expect any more messages from it.
1748 if (!base::NoBarrier_Load(&running_)) break;
1749 out_semaphore_.Wait();
1750 }
1751 return data;
1752}
1753
1754
1755void Worker::Terminate() {
1756 base::NoBarrier_Store(&running_, false);
1757 // Post NULL to wake the Worker thread message loop, and tell it to stop
1758 // running.
1759 PostMessage(NULL);
1760}
1761
1762
1763void Worker::WaitForThread() {
1764 Terminate();
1765 thread_->Join();
1766}
1767
1768
1769void Worker::ExecuteInThread() {
1770 Isolate::CreateParams create_params;
1771 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1772 Isolate* isolate = Isolate::New(create_params);
1773 {
1774 Isolate::Scope iscope(isolate);
1775 {
1776 HandleScope scope(isolate);
1777 PerIsolateData data(isolate);
1778 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1779 {
1780 Context::Scope cscope(context);
1781 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1782
1783 Local<Object> global = context->Global();
1784 Local<Value> this_value = External::New(isolate, this);
1785 Local<FunctionTemplate> postmessage_fun_template =
1786 FunctionTemplate::New(isolate, PostMessageOut, this_value);
1787
1788 Local<Function> postmessage_fun;
1789 if (postmessage_fun_template->GetFunction(context)
1790 .ToLocal(&postmessage_fun)) {
1791 global->Set(context, String::NewFromUtf8(isolate, "postMessage",
1792 NewStringType::kNormal)
1793 .ToLocalChecked(),
1794 postmessage_fun).FromJust();
1795 }
1796
1797 // First run the script
1798 Local<String> file_name =
1799 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1800 .ToLocalChecked();
1801 Local<String> source =
1802 String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
1803 .ToLocalChecked();
1804 if (Shell::ExecuteString(isolate, source, file_name, false, true)) {
1805 // Get the message handler
1806 Local<Value> onmessage =
1807 global->Get(context, String::NewFromUtf8(isolate, "onmessage",
1808 NewStringType::kNormal)
1809 .ToLocalChecked()).ToLocalChecked();
1810 if (onmessage->IsFunction()) {
1811 Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
1812 // Now wait for messages
1813 while (true) {
1814 in_semaphore_.Wait();
1815 SerializationData* data;
1816 if (!in_queue_.Dequeue(&data)) continue;
1817 if (data == NULL) {
1818 break;
1819 }
1820 int offset = 0;
1821 Local<Value> data_value;
1822 if (Shell::DeserializeValue(isolate, *data, &offset)
1823 .ToLocal(&data_value)) {
1824 Local<Value> argv[] = {data_value};
1825 (void)onmessage_fun->Call(context, global, 1, argv);
1826 }
1827 delete data;
1828 }
1829 }
1830 }
1831 }
1832 }
1833 Shell::CollectGarbage(isolate);
1834 }
1835 isolate->Dispose();
1836
1837 // Post NULL to wake the thread waiting on GetMessage() if there is one.
1838 out_queue_.Enqueue(NULL);
1839 out_semaphore_.Signal();
1840}
1841
1842
1843void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
1844 Isolate* isolate = args.GetIsolate();
1845 HandleScope handle_scope(isolate);
1846
1847 if (args.Length() < 1) {
1848 Throw(isolate, "Invalid argument");
1849 return;
1850 }
1851
1852 Local<Value> message = args[0];
1853
1854 // TODO(binji): Allow transferring from worker to main thread?
1855 Shell::ObjectList to_transfer;
1856
1857 Shell::ObjectList seen_objects;
1858 SerializationData* data = new SerializationData;
1859 if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects,
1860 data)) {
1861 DCHECK(args.Data()->IsExternal());
1862 Local<External> this_value = Local<External>::Cast(args.Data());
1863 Worker* worker = static_cast<Worker*>(this_value->Value());
1864 worker->out_queue_.Enqueue(data);
1865 worker->out_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001866 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001867 delete data;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001868 }
1869}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001870#endif // !V8_SHARED
1871
1872
1873void SetFlagsFromString(const char* flags) {
1874 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
1875}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001876
1877
1878bool Shell::SetOptions(int argc, char* argv[]) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879 bool logfile_per_isolate = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001880 for (int i = 0; i < argc; i++) {
1881 if (strcmp(argv[i], "--stress-opt") == 0) {
1882 options.stress_opt = true;
1883 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001884 } else if (strcmp(argv[i], "--nostress-opt") == 0) {
1885 options.stress_opt = false;
1886 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001887 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1888 options.stress_deopt = true;
1889 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001890 } else if (strcmp(argv[i], "--mock-arraybuffer-allocator") == 0) {
1891 options.mock_arraybuffer_allocator = true;
1892 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001893 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1894 // No support for stressing if we can't use --always-opt.
1895 options.stress_opt = false;
1896 options.stress_deopt = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001897 } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
1898 logfile_per_isolate = true;
1899 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001900 } else if (strcmp(argv[i], "--shell") == 0) {
1901 options.interactive_shell = true;
1902 argv[i] = NULL;
1903 } else if (strcmp(argv[i], "--test") == 0) {
1904 options.test_shell = true;
1905 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001906 } else if (strcmp(argv[i], "--notest") == 0 ||
1907 strcmp(argv[i], "--no-test") == 0) {
1908 options.test_shell = false;
1909 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001910 } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
1911 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001912 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001913 } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
1914 options.invoke_weak_callbacks = true;
1915 // TODO(jochen) See issue 3351
1916 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001917 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001918 } else if (strcmp(argv[i], "--omit-quit") == 0) {
1919 options.omit_quit = true;
1920 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001921 } else if (strcmp(argv[i], "-f") == 0) {
1922 // Ignore any -f flags for compatibility with other stand-alone
1923 // JavaScript engines.
1924 continue;
1925 } else if (strcmp(argv[i], "--isolate") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001926#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001927 printf("D8 with shared library does not support multi-threading\n");
1928 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001929#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001930 options.num_isolates++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001931 } else if (strcmp(argv[i], "--dump-heap-constants") == 0) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001932#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001933 printf("D8 with shared library does not support constant dumping\n");
Ben Murdoch589d6972011-11-30 16:04:58 +00001934 return false;
1935#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001936 options.dump_heap_constants = true;
1937 argv[i] = NULL;
Ben Murdoch589d6972011-11-30 16:04:58 +00001938#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001939 } else if (strcmp(argv[i], "--throws") == 0) {
1940 options.expected_to_throw = true;
1941 argv[i] = NULL;
1942 } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
1943 options.icu_data_file = argv[i] + 16;
1944 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001945#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001946 } else if (strcmp(argv[i], "--dump-counters") == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001947 printf("D8 with shared library does not include counters\n");
1948 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001949#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001950#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1951 } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
1952 options.natives_blob = argv[i] + 15;
1953 argv[i] = NULL;
1954 } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
1955 options.snapshot_blob = argv[i] + 16;
1956 argv[i] = NULL;
1957#endif // V8_USE_EXTERNAL_STARTUP_DATA
1958 } else if (strcmp(argv[i], "--cache") == 0 ||
1959 strncmp(argv[i], "--cache=", 8) == 0) {
1960 const char* value = argv[i] + 7;
1961 if (!*value || strncmp(value, "=code", 6) == 0) {
1962 options.compile_options = v8::ScriptCompiler::kProduceCodeCache;
1963 } else if (strncmp(value, "=parse", 7) == 0) {
1964 options.compile_options = v8::ScriptCompiler::kProduceParserCache;
1965 } else if (strncmp(value, "=none", 6) == 0) {
1966 options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
1967 } else {
1968 printf("Unknown option to --cache.\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001969 return false;
1970 }
1971 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001972 }
1973 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001974
1975 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1976
Ben Murdoch589d6972011-11-30 16:04:58 +00001977 // Set up isolated source groups.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001978 options.isolate_sources = new SourceGroup[options.num_isolates];
1979 SourceGroup* current = options.isolate_sources;
1980 current->Begin(argv, 1);
1981 for (int i = 1; i < argc; i++) {
1982 const char* str = argv[i];
1983 if (strcmp(str, "--isolate") == 0) {
1984 current->End(i);
1985 current++;
1986 current->Begin(argv, i + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001987 } else if (strcmp(str, "--module") == 0) {
1988 // Pass on to SourceGroup, which understands this option.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001989 } else if (strncmp(argv[i], "--", 2) == 0) {
1990 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001991 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
1992 options.script_executed = true;
1993 } else if (strncmp(str, "-", 1) != 0) {
1994 // Not a flag, so it must be a script to execute.
1995 options.script_executed = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001996 }
1997 }
1998 current->End(argc);
1999
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002000 if (!logfile_per_isolate && options.num_isolates) {
2001 SetFlagsFromString("--nologfile_per_isolate");
2002 }
2003
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002004 return true;
2005}
2006
2007
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002008int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002009#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002010 for (int i = 1; i < options.num_isolates; ++i) {
2011 options.isolate_sources[i].StartExecuteInThread();
2012 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002013#endif // !V8_SHARED
2014 {
2015 HandleScope scope(isolate);
2016 Local<Context> context = CreateEvaluationContext(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002017 if (last_run && options.use_interactive_shell()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002018 // Keep using the same context in the interactive shell.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002019 evaluation_context_.Reset(isolate, context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002020 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002021 {
2022 Context::Scope cscope(context);
2023 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2024 options.isolate_sources[0].Execute(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002025 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002026 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002027 CollectGarbage(isolate);
2028#ifndef V8_SHARED
2029 for (int i = 1; i < options.num_isolates; ++i) {
2030 if (last_run) {
2031 options.isolate_sources[i].JoinThread();
2032 } else {
2033 options.isolate_sources[i].WaitForThread();
2034 }
2035 }
2036 CleanupWorkers();
2037#endif // !V8_SHARED
2038 return 0;
2039}
2040
2041
2042void Shell::CollectGarbage(Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002043 if (options.send_idle_notification) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002044 const double kLongIdlePauseInSeconds = 1.0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002045 isolate->ContextDisposedNotification();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002046 isolate->IdleNotificationDeadline(
2047 g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002048 }
2049 if (options.invoke_weak_callbacks) {
2050 // By sending a low memory notifications, we will try hard to collect all
2051 // garbage and will therefore also invoke all weak callbacks of actually
2052 // unreachable persistent handles.
2053 isolate->LowMemoryNotification();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002054 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002055}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002056
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002057
2058void Shell::EmptyMessageQueues(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002059#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002060 if (!i::FLAG_verify_predictable) {
2061#endif
2062 while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue;
2063#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002064 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002065#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00002066}
2067
2068
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002069#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002070bool Shell::SerializeValue(Isolate* isolate, Local<Value> value,
2071 const ObjectList& to_transfer,
2072 ObjectList* seen_objects,
2073 SerializationData* out_data) {
2074 DCHECK(out_data);
2075 Local<Context> context = isolate->GetCurrentContext();
2076
2077 if (value->IsUndefined()) {
2078 out_data->WriteTag(kSerializationTagUndefined);
2079 } else if (value->IsNull()) {
2080 out_data->WriteTag(kSerializationTagNull);
2081 } else if (value->IsTrue()) {
2082 out_data->WriteTag(kSerializationTagTrue);
2083 } else if (value->IsFalse()) {
2084 out_data->WriteTag(kSerializationTagFalse);
2085 } else if (value->IsNumber()) {
2086 Local<Number> num = Local<Number>::Cast(value);
2087 double value = num->Value();
2088 out_data->WriteTag(kSerializationTagNumber);
2089 out_data->Write(value);
2090 } else if (value->IsString()) {
2091 v8::String::Utf8Value str(value);
2092 out_data->WriteTag(kSerializationTagString);
2093 out_data->Write(str.length());
2094 out_data->WriteMemory(*str, str.length());
2095 } else if (value->IsArray()) {
2096 Local<Array> array = Local<Array>::Cast(value);
2097 if (FindInObjectList(array, *seen_objects)) {
2098 Throw(isolate, "Duplicated arrays not supported");
2099 return false;
2100 }
2101 seen_objects->Add(array);
2102 out_data->WriteTag(kSerializationTagArray);
2103 uint32_t length = array->Length();
2104 out_data->Write(length);
2105 for (uint32_t i = 0; i < length; ++i) {
2106 Local<Value> element_value;
2107 if (array->Get(context, i).ToLocal(&element_value)) {
2108 if (!SerializeValue(isolate, element_value, to_transfer, seen_objects,
2109 out_data))
2110 return false;
2111 } else {
2112 Throw(isolate, "Failed to serialize array element.");
2113 return false;
2114 }
2115 }
2116 } else if (value->IsArrayBuffer()) {
2117 Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value);
2118 if (FindInObjectList(array_buffer, *seen_objects)) {
2119 Throw(isolate, "Duplicated array buffers not supported");
2120 return false;
2121 }
2122 seen_objects->Add(array_buffer);
2123 if (FindInObjectList(array_buffer, to_transfer)) {
2124 // Transfer ArrayBuffer
2125 if (!array_buffer->IsNeuterable()) {
2126 Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer");
2127 return false;
2128 }
2129
2130 ArrayBuffer::Contents contents = array_buffer->IsExternal()
2131 ? array_buffer->GetContents()
2132 : array_buffer->Externalize();
2133 array_buffer->Neuter();
2134 out_data->WriteArrayBufferContents(contents);
2135 } else {
2136 ArrayBuffer::Contents contents = array_buffer->GetContents();
2137 // Clone ArrayBuffer
2138 if (contents.ByteLength() > i::kMaxInt) {
2139 Throw(isolate, "ArrayBuffer is too big to clone");
2140 return false;
2141 }
2142
2143 int32_t byte_length = static_cast<int32_t>(contents.ByteLength());
2144 out_data->WriteTag(kSerializationTagArrayBuffer);
2145 out_data->Write(byte_length);
2146 out_data->WriteMemory(contents.Data(), byte_length);
2147 }
2148 } else if (value->IsSharedArrayBuffer()) {
2149 Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value);
2150 if (FindInObjectList(sab, *seen_objects)) {
2151 Throw(isolate, "Duplicated shared array buffers not supported");
2152 return false;
2153 }
2154 seen_objects->Add(sab);
2155 if (!FindInObjectList(sab, to_transfer)) {
2156 Throw(isolate, "SharedArrayBuffer must be transferred");
2157 return false;
2158 }
2159
2160 SharedArrayBuffer::Contents contents;
2161 if (sab->IsExternal()) {
2162 contents = sab->GetContents();
2163 } else {
2164 contents = sab->Externalize();
2165 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2166 externalized_shared_contents_.Add(contents);
2167 }
2168 out_data->WriteSharedArrayBufferContents(contents);
2169 } else if (value->IsObject()) {
2170 Local<Object> object = Local<Object>::Cast(value);
2171 if (FindInObjectList(object, *seen_objects)) {
2172 Throw(isolate, "Duplicated objects not supported");
2173 return false;
2174 }
2175 seen_objects->Add(object);
2176 Local<Array> property_names;
2177 if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
2178 Throw(isolate, "Unable to get property names");
2179 return false;
2180 }
2181
2182 uint32_t length = property_names->Length();
2183 out_data->WriteTag(kSerializationTagObject);
2184 out_data->Write(length);
2185 for (uint32_t i = 0; i < length; ++i) {
2186 Local<Value> name;
2187 Local<Value> property_value;
2188 if (property_names->Get(context, i).ToLocal(&name) &&
2189 object->Get(context, name).ToLocal(&property_value)) {
2190 if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data))
2191 return false;
2192 if (!SerializeValue(isolate, property_value, to_transfer, seen_objects,
2193 out_data))
2194 return false;
2195 } else {
2196 Throw(isolate, "Failed to serialize property.");
2197 return false;
2198 }
2199 }
2200 } else {
2201 Throw(isolate, "Don't know how to serialize object");
2202 return false;
2203 }
2204
2205 return true;
2206}
2207
2208
2209MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
2210 const SerializationData& data,
2211 int* offset) {
2212 DCHECK(offset);
2213 EscapableHandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002214 Local<Value> result;
2215 SerializationTag tag = data.ReadTag(offset);
2216
2217 switch (tag) {
2218 case kSerializationTagUndefined:
2219 result = Undefined(isolate);
2220 break;
2221 case kSerializationTagNull:
2222 result = Null(isolate);
2223 break;
2224 case kSerializationTagTrue:
2225 result = True(isolate);
2226 break;
2227 case kSerializationTagFalse:
2228 result = False(isolate);
2229 break;
2230 case kSerializationTagNumber:
2231 result = Number::New(isolate, data.Read<double>(offset));
2232 break;
2233 case kSerializationTagString: {
2234 int length = data.Read<int>(offset);
2235 CHECK(length >= 0);
2236 std::vector<char> buffer(length + 1); // + 1 so it is never empty.
2237 data.ReadMemory(&buffer[0], length, offset);
2238 MaybeLocal<String> str =
2239 String::NewFromUtf8(isolate, &buffer[0], NewStringType::kNormal,
2240 length).ToLocalChecked();
2241 if (!str.IsEmpty()) result = str.ToLocalChecked();
2242 break;
2243 }
2244 case kSerializationTagArray: {
2245 uint32_t length = data.Read<uint32_t>(offset);
2246 Local<Array> array = Array::New(isolate, length);
2247 for (uint32_t i = 0; i < length; ++i) {
2248 Local<Value> element_value;
2249 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value));
2250 array->Set(isolate->GetCurrentContext(), i, element_value).FromJust();
2251 }
2252 result = array;
2253 break;
2254 }
2255 case kSerializationTagObject: {
2256 int length = data.Read<int>(offset);
2257 Local<Object> object = Object::New(isolate);
2258 for (int i = 0; i < length; ++i) {
2259 Local<Value> property_name;
2260 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name));
2261 Local<Value> property_value;
2262 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value));
2263 object->Set(isolate->GetCurrentContext(), property_name, property_value)
2264 .FromJust();
2265 }
2266 result = object;
2267 break;
2268 }
2269 case kSerializationTagArrayBuffer: {
2270 int32_t byte_length = data.Read<int32_t>(offset);
2271 Local<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length);
2272 ArrayBuffer::Contents contents = array_buffer->GetContents();
2273 DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength());
2274 data.ReadMemory(contents.Data(), byte_length, offset);
2275 result = array_buffer;
2276 break;
2277 }
2278 case kSerializationTagTransferredArrayBuffer: {
2279 ArrayBuffer::Contents contents;
2280 data.ReadArrayBufferContents(&contents, offset);
2281 result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(),
2282 ArrayBufferCreationMode::kInternalized);
2283 break;
2284 }
2285 case kSerializationTagTransferredSharedArrayBuffer: {
2286 SharedArrayBuffer::Contents contents;
2287 data.ReadSharedArrayBufferContents(&contents, offset);
2288 result = SharedArrayBuffer::New(isolate, contents.Data(),
2289 contents.ByteLength());
2290 break;
2291 }
2292 default:
2293 UNREACHABLE();
2294 }
2295
2296 return scope.Escape(result);
2297}
2298
2299
2300void Shell::CleanupWorkers() {
2301 // Make a copy of workers_, because we don't want to call Worker::Terminate
2302 // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
2303 // create a new Worker, it would deadlock.
2304 i::List<Worker*> workers_copy;
2305 {
2306 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2307 allow_new_workers_ = false;
2308 workers_copy.AddAll(workers_);
2309 workers_.Clear();
2310 }
2311
2312 for (int i = 0; i < workers_copy.length(); ++i) {
2313 Worker* worker = workers_copy[i];
2314 worker->WaitForThread();
2315 delete worker;
2316 }
2317
2318 // Now that all workers are terminated, we can re-enable Worker creation.
2319 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2320 allow_new_workers_ = true;
2321
2322 for (int i = 0; i < externalized_shared_contents_.length(); ++i) {
2323 const SharedArrayBuffer::Contents& contents =
2324 externalized_shared_contents_[i];
2325 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
2326 }
2327 externalized_shared_contents_.Clear();
2328}
2329
2330
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002331static void DumpHeapConstants(i::Isolate* isolate) {
2332 i::Heap* heap = isolate->heap();
2333
2334 // Dump the INSTANCE_TYPES table to the console.
2335 printf("# List of known V8 instance types.\n");
2336#define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T);
2337 printf("INSTANCE_TYPES = {\n");
2338 INSTANCE_TYPE_LIST(DUMP_TYPE)
2339 printf("}\n");
2340#undef DUMP_TYPE
2341
2342 // Dump the KNOWN_MAP table to the console.
2343 printf("\n# List of known V8 maps.\n");
2344#define ROOT_LIST_CASE(type, name, camel_name) \
2345 if (n == NULL && o == heap->name()) n = #camel_name;
2346#define STRUCT_LIST_CASE(upper_name, camel_name, name) \
2347 if (n == NULL && o == heap->name##_map()) n = #camel_name "Map";
2348 i::HeapObjectIterator it(heap->map_space());
2349 printf("KNOWN_MAPS = {\n");
2350 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2351 i::Map* m = i::Map::cast(o);
2352 const char* n = NULL;
2353 intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
2354 int t = m->instance_type();
2355 ROOT_LIST(ROOT_LIST_CASE)
2356 STRUCT_LIST(STRUCT_LIST_CASE)
2357 if (n == NULL) continue;
2358 printf(" 0x%05" V8PRIxPTR ": (%d, \"%s\"),\n", p, t, n);
2359 }
2360 printf("}\n");
2361#undef STRUCT_LIST_CASE
2362#undef ROOT_LIST_CASE
2363
2364 // Dump the KNOWN_OBJECTS table to the console.
2365 printf("\n# List of known V8 objects.\n");
2366#define ROOT_LIST_CASE(type, name, camel_name) \
2367 if (n == NULL && o == heap->name()) n = #camel_name;
2368 i::OldSpaces spit(heap);
2369 printf("KNOWN_OBJECTS = {\n");
2370 for (i::PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
2371 i::HeapObjectIterator it(s);
2372 const char* sname = AllocationSpaceName(s->identity());
2373 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2374 const char* n = NULL;
2375 intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
2376 ROOT_LIST(ROOT_LIST_CASE)
2377 if (n == NULL) continue;
2378 printf(" (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", sname, p, n);
2379 }
2380 }
2381 printf("}\n");
2382#undef ROOT_LIST_CASE
2383}
2384#endif // !V8_SHARED
2385
2386
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002387int Shell::Main(int argc, char* argv[]) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002388#if (defined(_WIN32) || defined(_WIN64))
2389 UINT new_flags =
2390 SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
2391 UINT existing_flags = SetErrorMode(new_flags);
2392 SetErrorMode(existing_flags | new_flags);
2393#if defined(_MSC_VER)
2394 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2395 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
2396 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2397 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
2398 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2399 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
2400 _set_error_mode(_OUT_TO_STDERR);
2401#endif // defined(_MSC_VER)
2402#endif // defined(_WIN32) || defined(_WIN64)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002403 if (!SetOptions(argc, argv)) return 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002404 v8::V8::InitializeICU(options.icu_data_file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002405#ifndef V8_SHARED
2406 g_platform = i::FLAG_verify_predictable
2407 ? new PredictablePlatform()
2408 : v8::platform::CreateDefaultPlatform();
2409#else
2410 g_platform = v8::platform::CreateDefaultPlatform();
2411#endif // !V8_SHARED
2412
2413 v8::V8::InitializePlatform(g_platform);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002414 v8::V8::Initialize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002415 if (options.natives_blob || options.snapshot_blob) {
2416 v8::V8::InitializeExternalStartupData(options.natives_blob,
2417 options.snapshot_blob);
2418 } else {
2419 v8::V8::InitializeExternalStartupData(argv[0]);
2420 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002421 SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002422 SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002423 SetFlagsFromString("--redirect-code-traces-to=code.asm");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002424 int result = 0;
2425 Isolate::CreateParams create_params;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002426 ShellArrayBufferAllocator shell_array_buffer_allocator;
2427 MockArrayBufferAllocator mock_arraybuffer_allocator;
2428 if (options.mock_arraybuffer_allocator) {
2429 Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
2430 } else {
2431 Shell::array_buffer_allocator = &shell_array_buffer_allocator;
2432 }
2433 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002434#ifdef ENABLE_VTUNE_JIT_INTERFACE
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002435 create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002436#endif
2437#ifndef V8_SHARED
2438 create_params.constraints.ConfigureDefaults(
2439 base::SysInfo::AmountOfPhysicalMemory(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002440 base::SysInfo::AmountOfVirtualMemory());
2441
2442 Shell::counter_map_ = new CounterMap();
2443 if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
2444 create_params.counter_lookup_callback = LookupCounter;
2445 create_params.create_histogram_callback = CreateHistogram;
2446 create_params.add_histogram_sample_callback = AddHistogramSample;
2447 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002448#endif
2449 Isolate* isolate = Isolate::New(create_params);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002450 {
2451 Isolate::Scope scope(isolate);
2452 Initialize(isolate);
2453 PerIsolateData data(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002454
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002455#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002456 if (options.dump_heap_constants) {
2457 DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate));
2458 return 0;
2459 }
2460#endif
2461
2462 if (options.stress_opt || options.stress_deopt) {
2463 Testing::SetStressRunType(options.stress_opt
2464 ? Testing::kStressTypeOpt
2465 : Testing::kStressTypeDeopt);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002466 options.stress_runs = Testing::GetStressRuns();
2467 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2468 printf("============ Stress %d/%d ============\n", i + 1,
2469 options.stress_runs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002470 Testing::PrepareStressRun(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002471 bool last_run = i == options.stress_runs - 1;
2472 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002473 }
2474 printf("======== Full Deoptimization =======\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002475 Testing::DeoptimizeAll(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002476#if !defined(V8_SHARED)
2477 } else if (i::FLAG_stress_runs > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002478 options.stress_runs = i::FLAG_stress_runs;
2479 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2480 printf("============ Run %d/%d ============\n", i + 1,
2481 options.stress_runs);
2482 bool last_run = i == options.stress_runs - 1;
2483 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002484 }
2485#endif
2486 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002487 bool last_run = true;
2488 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002489 }
2490
2491 // Run interactive shell if explicitly requested or if no script has been
2492 // executed, but never on --test
2493 if (options.use_interactive_shell()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002494 RunShell(isolate);
2495 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002496
Ben Murdochc5610432016-08-08 18:44:38 +01002497#ifndef V8_SHARED
2498 if (i::FLAG_ignition && i::FLAG_trace_ignition_dispatches &&
2499 i::FLAG_trace_ignition_dispatches_output_file != nullptr) {
2500 WriteIgnitionDispatchCountersFile(isolate);
2501 }
2502#endif
2503
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002504 // Shut down contexts and collect garbage.
2505 evaluation_context_.Reset();
2506#ifndef V8_SHARED
Ben Murdochda12d292016-06-02 14:46:10 +01002507 stringify_function_.Reset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002508#endif // !V8_SHARED
2509 CollectGarbage(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002510 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002511 OnExit(isolate);
2512#ifndef V8_SHARED
2513 // Dump basic block profiling data.
2514 if (i::BasicBlockProfiler* profiler =
2515 reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
2516 i::OFStream os(stdout);
2517 os << *profiler;
2518 }
2519#endif // !V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002520 isolate->Dispose();
2521 V8::Dispose();
2522 V8::ShutdownPlatform();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002523 delete g_platform;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002524
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002525 return result;
2526}
2527
Steve Blocka7e24c12009-10-30 11:49:00 +00002528} // namespace v8
2529
2530
Ben Murdoch257744e2011-11-30 15:57:28 +00002531#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +00002532int main(int argc, char* argv[]) {
2533 return v8::Shell::Main(argc, argv);
2534}
Ben Murdoch257744e2011-11-30 15:57:28 +00002535#endif