blob: 7b6270745bad9a3b09d28aebb836d8dcb65fddca [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);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100341 // TODO(adamk): Make use of compile options for Modules.
342 if (compile_options == ScriptCompiler::kNoCompileOptions ||
343 source_type == MODULE) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400344 ScriptCompiler::Source script_source(source, origin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000345 return source_type == SCRIPT
346 ? ScriptCompiler::Compile(context, &script_source,
347 compile_options)
348 : ScriptCompiler::CompileModule(context, &script_source,
349 compile_options);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000350 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400351
352 ScriptCompiler::CachedData* data =
353 CompileForCachedData(source, name, compile_options);
354 ScriptCompiler::Source cached_source(source, origin, data);
355 if (compile_options == ScriptCompiler::kProduceCodeCache) {
356 compile_options = ScriptCompiler::kConsumeCodeCache;
357 } else if (compile_options == ScriptCompiler::kProduceParserCache) {
358 compile_options = ScriptCompiler::kConsumeParserCache;
359 } else {
360 DCHECK(false); // A new compile option?
361 }
362 if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100363 DCHECK_EQ(SCRIPT, source_type);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000364 MaybeLocal<Script> result =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100365 ScriptCompiler::Compile(context, &cached_source, compile_options);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 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
Ben Murdoch61f157c2016-09-16 13:49:30 +0100526MaybeLocal<Context> Shell::CreateRealm(
527 const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000528 Isolate* isolate = args.GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000529 TryCatch try_catch(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000530 PerIsolateData* data = PerIsolateData::Get(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000531 Global<Context>* old_realms = data->realms_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000532 int index = data->realm_count_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000533 data->realms_ = new Global<Context>[++data->realm_count_];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000534 for (int i = 0; i < index; ++i) {
535 data->realms_[i].Reset(isolate, old_realms[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000536 old_realms[i].Reset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000537 }
538 delete[] old_realms;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000539 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
540 Local<Context> context = Context::New(isolate, NULL, global_template);
541 if (context.IsEmpty()) {
542 DCHECK(try_catch.HasCaught());
543 try_catch.ReThrow();
Ben Murdoch61f157c2016-09-16 13:49:30 +0100544 return MaybeLocal<Context>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000545 }
546 data->realms_[index].Reset(isolate, context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000547 args.GetReturnValue().Set(index);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100548 return context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000549}
550
Ben Murdoch61f157c2016-09-16 13:49:30 +0100551// Realm.create() creates a new realm with a distinct security token
552// and returns its index.
553void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
554 CreateRealm(args);
555}
556
557// Realm.createAllowCrossRealmAccess() creates a new realm with the same
558// security token as the current realm.
559void Shell::RealmCreateAllowCrossRealmAccess(
560 const v8::FunctionCallbackInfo<v8::Value>& args) {
561 Local<Context> context;
562 if (CreateRealm(args).ToLocal(&context)) {
563 context->SetSecurityToken(
564 args.GetIsolate()->GetEnteredContext()->GetSecurityToken());
565 }
566}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000567
568// Realm.dispose(i) disposes the reference to the realm i.
569void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
570 Isolate* isolate = args.GetIsolate();
571 PerIsolateData* data = PerIsolateData::Get(isolate);
572 int index = data->RealmIndexOrThrow(args, 0);
573 if (index == -1) return;
574 if (index == 0 ||
575 index == data->realm_current_ || index == data->realm_switch_) {
576 Throw(args.GetIsolate(), "Invalid realm index");
577 return;
578 }
579 data->realms_[index].Reset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000580 isolate->ContextDisposedNotification();
581 isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000582}
583
584
585// Realm.switch(i) switches to the realm i for consecutive interactive inputs.
586void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
587 Isolate* isolate = args.GetIsolate();
588 PerIsolateData* data = PerIsolateData::Get(isolate);
589 int index = data->RealmIndexOrThrow(args, 0);
590 if (index == -1) return;
591 data->realm_switch_ = index;
592}
593
594
595// Realm.eval(i, s) evaluates s in realm i and returns the result.
596void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
597 Isolate* isolate = args.GetIsolate();
598 PerIsolateData* data = PerIsolateData::Get(isolate);
599 int index = data->RealmIndexOrThrow(args, 0);
600 if (index == -1) return;
601 if (args.Length() < 2 || !args[1]->IsString()) {
602 Throw(args.GetIsolate(), "Invalid argument");
603 return;
604 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000605 ScriptCompiler::Source script_source(
606 args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
607 Local<UnboundScript> script;
608 if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
609 .ToLocal(&script)) {
610 return;
611 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000612 Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
613 realm->Enter();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000614 Local<Value> result;
615 if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
616 realm->Exit();
617 return;
618 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000619 realm->Exit();
620 args.GetReturnValue().Set(result);
621}
622
623
624// Realm.shared is an accessor for a single shared value across realms.
625void Shell::RealmSharedGet(Local<String> property,
626 const PropertyCallbackInfo<Value>& info) {
627 Isolate* isolate = info.GetIsolate();
628 PerIsolateData* data = PerIsolateData::Get(isolate);
629 if (data->realm_shared_.IsEmpty()) return;
630 info.GetReturnValue().Set(data->realm_shared_);
631}
632
633void Shell::RealmSharedSet(Local<String> property,
634 Local<Value> value,
635 const PropertyCallbackInfo<void>& info) {
636 Isolate* isolate = info.GetIsolate();
637 PerIsolateData* data = PerIsolateData::Get(isolate);
638 data->realm_shared_.Reset(isolate, value);
639}
640
641
642void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
643 Write(args);
644 printf("\n");
645 fflush(stdout);
646}
647
648
649void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000650 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000651 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000652 if (i != 0) {
653 printf(" ");
654 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000655
656 // Explicitly catch potential exceptions in toString().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000657 v8::TryCatch try_catch(args.GetIsolate());
658 Local<Value> arg = args[i];
659 Local<String> str_obj;
660
661 if (arg->IsSymbol()) {
662 arg = Local<Symbol>::Cast(arg)->Name();
663 }
664 if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
665 .ToLocal(&str_obj)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000666 try_catch.ReThrow();
667 return;
668 }
669
670 v8::String::Utf8Value str(str_obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000671 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
Steve Blockd0582a62009-12-15 09:54:21 +0000672 if (n != str.length()) {
673 printf("Error in fwrite\n");
Ben Murdoch589d6972011-11-30 16:04:58 +0000674 Exit(1);
Steve Blockd0582a62009-12-15 09:54:21 +0000675 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000676 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000677}
678
679
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000680void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000681 String::Utf8Value file(args[0]);
682 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000683 Throw(args.GetIsolate(), "Error loading file");
684 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000685 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000686 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000687 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000688 Throw(args.GetIsolate(), "Error loading file");
689 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000690 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000691 args.GetReturnValue().Set(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000692}
693
694
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000695Local<String> Shell::ReadFromStdin(Isolate* isolate) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000696 static const int kBufferSize = 256;
697 char buffer[kBufferSize];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000698 Local<String> accumulator =
699 String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000700 int length;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000701 while (true) {
702 // Continue reading if the line ends with an escape '\\' or the line has
703 // not been fully read into the buffer yet (does not end with '\n').
704 // If fgets gets an error, just give up.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100705 char* input = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000706 input = fgets(buffer, kBufferSize, stdin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000707 if (input == NULL) return Local<String>();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000708 length = static_cast<int>(strlen(buffer));
709 if (length == 0) {
710 return accumulator;
711 } else if (buffer[length-1] != '\n') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000712 accumulator = String::Concat(
713 accumulator,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000714 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
715 .ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000716 } else if (length > 1 && buffer[length-2] == '\\') {
717 buffer[length-2] = '\n';
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000718 accumulator = String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000719 accumulator,
720 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
721 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000722 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000723 return String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000724 accumulator,
725 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
726 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000727 }
728 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000729}
730
731
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000732void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000733 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000734 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000735 String::Utf8Value file(args[i]);
736 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000737 Throw(args.GetIsolate(), "Error loading file");
738 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000739 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000740 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000741 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000742 Throw(args.GetIsolate(), "Error loading file");
743 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000744 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000745 if (!ExecuteString(
746 args.GetIsolate(), source,
747 String::NewFromUtf8(args.GetIsolate(), *file,
748 NewStringType::kNormal).ToLocalChecked(),
749 false, true)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000750 Throw(args.GetIsolate(), "Error executing file");
751 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000752 }
753 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100754}
755
756
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000757#ifndef V8_SHARED
758void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
759 Isolate* isolate = args.GetIsolate();
760 HandleScope handle_scope(isolate);
761 if (args.Length() < 1 || !args[0]->IsString()) {
762 Throw(args.GetIsolate(), "1st argument must be string");
763 return;
764 }
765
766 if (!args.IsConstructCall()) {
767 Throw(args.GetIsolate(), "Worker must be constructed with new");
768 return;
769 }
770
771 {
772 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
773 if (workers_.length() >= kMaxWorkers) {
774 Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
775 return;
776 }
777
778 // Initialize the internal field to NULL; if we return early without
779 // creating a new Worker (because the main thread is terminating) we can
780 // early-out from the instance calls.
781 args.Holder()->SetAlignedPointerInInternalField(0, NULL);
782
783 if (!allow_new_workers_) return;
784
785 Worker* worker = new Worker;
786 args.Holder()->SetAlignedPointerInInternalField(0, worker);
787 workers_.Add(worker);
788
789 String::Utf8Value script(args[0]);
790 if (!*script) {
791 Throw(args.GetIsolate(), "Can't get worker script");
792 return;
793 }
794 worker->StartExecuteInThread(*script);
795 }
796}
797
798
799void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
800 Isolate* isolate = args.GetIsolate();
801 HandleScope handle_scope(isolate);
802 Local<Context> context = isolate->GetCurrentContext();
803
804 if (args.Length() < 1) {
805 Throw(isolate, "Invalid argument");
806 return;
807 }
808
809 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
810 if (!worker) {
811 return;
812 }
813
814 Local<Value> message = args[0];
815 ObjectList to_transfer;
816 if (args.Length() >= 2) {
817 if (!args[1]->IsArray()) {
818 Throw(isolate, "Transfer list must be an Array");
819 return;
820 }
821
822 Local<Array> transfer = Local<Array>::Cast(args[1]);
823 uint32_t length = transfer->Length();
824 for (uint32_t i = 0; i < length; ++i) {
825 Local<Value> element;
826 if (transfer->Get(context, i).ToLocal(&element)) {
827 if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) {
828 Throw(isolate,
829 "Transfer array elements must be an ArrayBuffer or "
830 "SharedArrayBuffer.");
831 break;
832 }
833
834 to_transfer.Add(Local<Object>::Cast(element));
835 }
836 }
837 }
838
839 ObjectList seen_objects;
840 SerializationData* data = new SerializationData;
841 if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) {
842 worker->PostMessage(data);
843 } else {
844 delete data;
845 }
846}
847
848
849void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
850 Isolate* isolate = args.GetIsolate();
851 HandleScope handle_scope(isolate);
852 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
853 if (!worker) {
854 return;
855 }
856
857 SerializationData* data = worker->GetMessage();
858 if (data) {
859 int offset = 0;
860 Local<Value> data_value;
861 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
862 args.GetReturnValue().Set(data_value);
863 }
864 delete data;
865 }
866}
867
868
869void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
870 Isolate* isolate = args.GetIsolate();
871 HandleScope handle_scope(isolate);
872 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
873 if (!worker) {
874 return;
875 }
876
877 worker->Terminate();
878}
879#endif // !V8_SHARED
880
881
882void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
883 int exit_code = (*args)[0]
884 ->Int32Value(args->GetIsolate()->GetCurrentContext())
885 .FromMaybe(0);
886#ifndef V8_SHARED
887 CleanupWorkers();
888#endif // !V8_SHARED
889 OnExit(args->GetIsolate());
890 Exit(exit_code);
891}
892
893
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000894void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000895 base::CallOnce(&quit_once_, &QuitOnce,
896 const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
Steve Blocka7e24c12009-10-30 11:49:00 +0000897}
898
899
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000900void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
901 args.GetReturnValue().Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000902 String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
903 NewStringType::kNormal).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000904}
905
906
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000907void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
908 HandleScope handle_scope(isolate);
909#ifndef V8_SHARED
Ben Murdochda12d292016-06-02 14:46:10 +0100910 Local<Context> context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000911 bool enter_context = !isolate->InContext();
912 if (enter_context) {
Ben Murdochda12d292016-06-02 14:46:10 +0100913 context = Local<Context>::New(isolate, evaluation_context_);
914 context->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000915 }
916#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000917 v8::String::Utf8Value exception(try_catch->Exception());
918 const char* exception_string = ToCString(exception);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000919 Local<Message> message = try_catch->Message();
Steve Blocka7e24c12009-10-30 11:49:00 +0000920 if (message.IsEmpty()) {
921 // V8 didn't provide any extra information about this error; just
922 // print the exception.
923 printf("%s\n", exception_string);
924 } else {
925 // Print (filename):(line number): (message).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000926 v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
Steve Blocka7e24c12009-10-30 11:49:00 +0000927 const char* filename_string = ToCString(filename);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100928 Maybe<int> maybeline = message->GetLineNumber(isolate->GetCurrentContext());
929 int linenum = maybeline.IsJust() ? maybeline.FromJust() : -1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000930 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100931 Local<String> sourceline;
932 if (message->GetSourceLine(isolate->GetCurrentContext())
933 .ToLocal(&sourceline)) {
934 // Print line of source code.
935 v8::String::Utf8Value sourcelinevalue(sourceline);
936 const char* sourceline_string = ToCString(sourcelinevalue);
937 printf("%s\n", sourceline_string);
938 // Print wavy underline (GetUnderline is deprecated).
939 int start =
940 message->GetStartColumn(isolate->GetCurrentContext()).FromJust();
941 for (int i = 0; i < start; i++) {
942 printf(" ");
943 }
944 int end = message->GetEndColumn(isolate->GetCurrentContext()).FromJust();
945 for (int i = start; i < end; i++) {
946 printf("^");
947 }
948 printf("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000949 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000950 Local<Value> stack_trace_string;
951 if (try_catch->StackTrace(isolate->GetCurrentContext())
952 .ToLocal(&stack_trace_string) &&
953 stack_trace_string->IsString()) {
954 v8::String::Utf8Value stack_trace(
955 Local<String>::Cast(stack_trace_string));
956 printf("%s\n", ToCString(stack_trace));
Ben Murdoch257744e2011-11-30 15:57:28 +0000957 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000958 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000959 printf("\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000960#ifndef V8_SHARED
Ben Murdochda12d292016-06-02 14:46:10 +0100961 if (enter_context) context->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000962#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000963}
964
965
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000966#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000967int32_t* Counter::Bind(const char* name, bool is_histogram) {
968 int i;
969 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
970 name_[i] = static_cast<char>(name[i]);
971 name_[i] = '\0';
972 is_histogram_ = is_histogram;
973 return ptr();
974}
975
976
977void Counter::AddSample(int32_t sample) {
978 count_++;
979 sample_total_ += sample;
980}
981
982
983CounterCollection::CounterCollection() {
984 magic_number_ = 0xDEADFACE;
985 max_counters_ = kMaxCounters;
986 max_name_size_ = Counter::kMaxNameSize;
987 counters_in_use_ = 0;
988}
989
990
991Counter* CounterCollection::GetNextCounter() {
992 if (counters_in_use_ == kMaxCounters) return NULL;
993 return &counters_[counters_in_use_++];
994}
995
996
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000997void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
998 counters_file_ = base::OS::MemoryMappedFile::create(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000999 name, sizeof(CounterCollection), &local_counters_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001000 void* memory = (counters_file_ == NULL) ?
1001 NULL : counters_file_->memory();
1002 if (memory == NULL) {
1003 printf("Could not map counters file %s\n", name);
Ben Murdoch589d6972011-11-30 16:04:58 +00001004 Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001005 }
1006 counters_ = static_cast<CounterCollection*>(memory);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001007 isolate->SetCounterFunction(LookupCounter);
1008 isolate->SetCreateHistogramFunction(CreateHistogram);
1009 isolate->SetAddHistogramSampleFunction(AddHistogramSample);
Steve Blocka7e24c12009-10-30 11:49:00 +00001010}
1011
1012
1013int CounterMap::Hash(const char* name) {
1014 int h = 0;
1015 int c;
1016 while ((c = *name++) != 0) {
1017 h += h << 5;
1018 h += c;
1019 }
1020 return h;
1021}
1022
1023
1024Counter* Shell::GetCounter(const char* name, bool is_histogram) {
1025 Counter* counter = counter_map_->Lookup(name);
1026
1027 if (counter == NULL) {
1028 counter = counters_->GetNextCounter();
1029 if (counter != NULL) {
1030 counter_map_->Set(name, counter);
1031 counter->Bind(name, is_histogram);
1032 }
1033 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001034 DCHECK(counter->is_histogram() == is_histogram);
Steve Blocka7e24c12009-10-30 11:49:00 +00001035 }
1036 return counter;
1037}
1038
1039
1040int* Shell::LookupCounter(const char* name) {
1041 Counter* counter = GetCounter(name, false);
1042
1043 if (counter != NULL) {
1044 return counter->ptr();
1045 } else {
1046 return NULL;
1047 }
1048}
1049
1050
1051void* Shell::CreateHistogram(const char* name,
1052 int min,
1053 int max,
1054 size_t buckets) {
1055 return GetCounter(name, true);
1056}
1057
1058
1059void Shell::AddHistogramSample(void* histogram, int sample) {
1060 Counter* counter = reinterpret_cast<Counter*>(histogram);
1061 counter->AddSample(sample);
1062}
1063
Ben Murdochda12d292016-06-02 14:46:10 +01001064// Turn a value into a human-readable string.
1065Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
1066 v8::Local<v8::Context> context =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001067 v8::Local<v8::Context>::New(isolate, evaluation_context_);
Ben Murdochda12d292016-06-02 14:46:10 +01001068 if (stringify_function_.IsEmpty()) {
1069 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
1070 i::Vector<const char> source_string =
1071 i::NativesCollection<i::D8>::GetScriptSource(source_index);
1072 i::Vector<const char> source_name =
1073 i::NativesCollection<i::D8>::GetScriptName(source_index);
1074 Local<String> source =
1075 String::NewFromUtf8(isolate, source_string.start(),
1076 NewStringType::kNormal, source_string.length())
1077 .ToLocalChecked();
1078 Local<String> name =
1079 String::NewFromUtf8(isolate, source_name.start(),
1080 NewStringType::kNormal, source_name.length())
1081 .ToLocalChecked();
1082 ScriptOrigin origin(name);
1083 Local<Script> script =
1084 Script::Compile(context, source, &origin).ToLocalChecked();
1085 stringify_function_.Reset(
1086 isolate, script->Run(context).ToLocalChecked().As<Function>());
1087 }
1088 Local<Function> fun = Local<Function>::New(isolate, stringify_function_);
1089 Local<Value> argv[1] = {value};
1090 v8::TryCatch try_catch(isolate);
1091 MaybeLocal<Value> result =
1092 fun->Call(context, Undefined(isolate), 1, argv).ToLocalChecked();
1093 if (result.IsEmpty()) return String::Empty(isolate);
1094 return result.ToLocalChecked().As<String>();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001095}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001096#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001097
1098
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001099Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
1100 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
1101 global_template->Set(
1102 String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
1103 .ToLocalChecked(),
1104 FunctionTemplate::New(isolate, Print));
1105 global_template->Set(
1106 String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
1107 .ToLocalChecked(),
1108 FunctionTemplate::New(isolate, Write));
1109 global_template->Set(
1110 String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
1111 .ToLocalChecked(),
1112 FunctionTemplate::New(isolate, Read));
1113 global_template->Set(
1114 String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
1115 .ToLocalChecked(),
1116 FunctionTemplate::New(isolate, ReadBuffer));
1117 global_template->Set(
1118 String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
1119 .ToLocalChecked(),
1120 FunctionTemplate::New(isolate, ReadLine));
1121 global_template->Set(
1122 String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
1123 .ToLocalChecked(),
1124 FunctionTemplate::New(isolate, Load));
1125 // Some Emscripten-generated code tries to call 'quit', which in turn would
1126 // call C's exit(). This would lead to memory leaks, because there is no way
1127 // we can terminate cleanly then, so we need a way to hide 'quit'.
1128 if (!options.omit_quit) {
1129 global_template->Set(
1130 String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
1131 .ToLocalChecked(),
1132 FunctionTemplate::New(isolate, Quit));
1133 }
1134 global_template->Set(
1135 String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
1136 .ToLocalChecked(),
1137 FunctionTemplate::New(isolate, Version));
Ben Murdoch61f157c2016-09-16 13:49:30 +01001138 global_template->Set(
1139 Symbol::GetToStringTag(isolate),
1140 String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1141 .ToLocalChecked());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001142
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001143 // Bind the Realm object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001144 Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
1145 realm_template->Set(
1146 String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
1147 .ToLocalChecked(),
1148 FunctionTemplate::New(isolate, RealmCurrent));
1149 realm_template->Set(
1150 String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
1151 .ToLocalChecked(),
1152 FunctionTemplate::New(isolate, RealmOwner));
1153 realm_template->Set(
1154 String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1155 .ToLocalChecked(),
1156 FunctionTemplate::New(isolate, RealmGlobal));
1157 realm_template->Set(
1158 String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
1159 .ToLocalChecked(),
1160 FunctionTemplate::New(isolate, RealmCreate));
1161 realm_template->Set(
Ben Murdoch61f157c2016-09-16 13:49:30 +01001162 String::NewFromUtf8(isolate, "createAllowCrossRealmAccess",
1163 NewStringType::kNormal)
1164 .ToLocalChecked(),
1165 FunctionTemplate::New(isolate, RealmCreateAllowCrossRealmAccess));
1166 realm_template->Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001167 String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
1168 .ToLocalChecked(),
1169 FunctionTemplate::New(isolate, RealmDispose));
1170 realm_template->Set(
1171 String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
1172 .ToLocalChecked(),
1173 FunctionTemplate::New(isolate, RealmSwitch));
1174 realm_template->Set(
1175 String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
1176 .ToLocalChecked(),
1177 FunctionTemplate::New(isolate, RealmEval));
1178 realm_template->SetAccessor(
1179 String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
1180 .ToLocalChecked(),
1181 RealmSharedGet, RealmSharedSet);
1182 global_template->Set(
1183 String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
1184 .ToLocalChecked(),
1185 realm_template);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001186
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001187#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001188 Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
1189 performance_template->Set(
1190 String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
1191 .ToLocalChecked(),
1192 FunctionTemplate::New(isolate, PerformanceNow));
1193 global_template->Set(
1194 String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
1195 .ToLocalChecked(),
1196 performance_template);
1197
1198 Local<FunctionTemplate> worker_fun_template =
1199 FunctionTemplate::New(isolate, WorkerNew);
1200 Local<Signature> worker_signature =
1201 Signature::New(isolate, worker_fun_template);
1202 worker_fun_template->SetClassName(
1203 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1204 .ToLocalChecked());
1205 worker_fun_template->ReadOnlyPrototype();
1206 worker_fun_template->PrototypeTemplate()->Set(
1207 String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
1208 .ToLocalChecked(),
1209 FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
1210 worker_signature));
1211 worker_fun_template->PrototypeTemplate()->Set(
1212 String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
1213 .ToLocalChecked(),
1214 FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
1215 worker_signature));
1216 worker_fun_template->PrototypeTemplate()->Set(
1217 String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
1218 .ToLocalChecked(),
1219 FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
1220 worker_signature));
1221 worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
1222 global_template->Set(
1223 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1224 .ToLocalChecked(),
1225 worker_fun_template);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001226#endif // !V8_SHARED
1227
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001228 Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001229 AddOSMethods(isolate, os_templ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001230 global_template->Set(
1231 String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
1232 .ToLocalChecked(),
1233 os_templ);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001234
1235 return global_template;
Steve Blocka7e24c12009-10-30 11:49:00 +00001236}
1237
Ben Murdoch097c5b22016-05-18 11:27:45 +01001238static void EmptyMessageCallback(Local<Message> message, Local<Value> error) {
1239 // Nothing to be done here, exceptions thrown up to the shell will be reported
1240 // separately by {Shell::ReportException} after they are caught.
1241}
Steve Blocka7e24c12009-10-30 11:49:00 +00001242
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243void Shell::Initialize(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001244#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001245 // Set up counters
1246 if (i::StrLength(i::FLAG_map_counters) != 0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001247 MapCounters(isolate, i::FLAG_map_counters);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001248#endif // !V8_SHARED
Ben Murdoch097c5b22016-05-18 11:27:45 +01001249 // Disable default message reporting.
1250 isolate->AddMessageListener(EmptyMessageCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001251}
1252
1253
1254Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001255#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001256 // This needs to be a critical section since this is not thread-safe
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001257 base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001258#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001259 // Initialize the global objects
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001260 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001261 EscapableHandleScope handle_scope(isolate);
1262 Local<Context> context = Context::New(isolate, NULL, global_template);
1263 DCHECK(!context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001264 Context::Scope scope(context);
1265
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001266#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001267 i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001268 i::JSArguments js_args = i::FLAG_js_arguments;
1269 i::Handle<i::FixedArray> arguments_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001270 factory->NewFixedArray(js_args.argc);
1271 for (int j = 0; j < js_args.argc; j++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001272 i::Handle<i::String> arg =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001273 factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001274 arguments_array->set(j, *arg);
1275 }
1276 i::Handle<i::JSArray> arguments_jsarray =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001277 factory->NewJSArrayWithElements(arguments_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001278 context->Global()
1279 ->Set(context,
1280 String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
1281 .ToLocalChecked(),
1282 Utils::ToLocal(arguments_jsarray))
1283 .FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001284#endif // !V8_SHARED
1285 return handle_scope.Escape(context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001286}
1287
1288
Ben Murdoch589d6972011-11-30 16:04:58 +00001289void Shell::Exit(int exit_code) {
1290 // Use _exit instead of exit to avoid races between isolate
1291 // threads and static destructors.
1292 fflush(stdout);
1293 fflush(stderr);
1294 _exit(exit_code);
1295}
1296
1297
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001298#ifndef V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001299struct CounterAndKey {
1300 Counter* counter;
1301 const char* key;
1302};
1303
1304
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001305inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
1306 return strcmp(lhs.key, rhs.key) < 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001307}
Ben Murdochc5610432016-08-08 18:44:38 +01001308
1309void Shell::WriteIgnitionDispatchCountersFile(v8::Isolate* isolate) {
1310 HandleScope handle_scope(isolate);
1311 Local<Context> context = Context::New(isolate);
1312 Context::Scope context_scope(context);
1313
1314 Local<Object> dispatch_counters = reinterpret_cast<i::Isolate*>(isolate)
1315 ->interpreter()
1316 ->GetDispatchCountersObject();
1317 std::ofstream dispatch_counters_stream(
1318 i::FLAG_trace_ignition_dispatches_output_file);
1319 dispatch_counters_stream << *String::Utf8Value(
1320 JSON::Stringify(context, dispatch_counters).ToLocalChecked());
1321}
1322
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001323#endif // !V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001324
1325
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001326void Shell::OnExit(v8::Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001327#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001328 if (i::FLAG_dump_counters) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001329 int number_of_counters = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001330 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001331 number_of_counters++;
1332 }
1333 CounterAndKey* counters = new CounterAndKey[number_of_counters];
1334 int j = 0;
1335 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
1336 counters[j].counter = i.CurrentValue();
1337 counters[j].key = i.CurrentKey();
1338 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001339 std::sort(counters, counters + number_of_counters);
1340 printf("+----------------------------------------------------------------+"
1341 "-------------+\n");
1342 printf("| Name |"
1343 " Value |\n");
1344 printf("+----------------------------------------------------------------+"
1345 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001346 for (j = 0; j < number_of_counters; j++) {
1347 Counter* counter = counters[j].counter;
1348 const char* key = counters[j].key;
Steve Blocka7e24c12009-10-30 11:49:00 +00001349 if (counter->is_histogram()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001350 printf("| c:%-60s | %11i |\n", key, counter->count());
1351 printf("| t:%-60s | %11i |\n", key, counter->sample_total());
Steve Blocka7e24c12009-10-30 11:49:00 +00001352 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001353 printf("| %-62s | %11i |\n", key, counter->count());
Steve Blocka7e24c12009-10-30 11:49:00 +00001354 }
1355 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001356 printf("+----------------------------------------------------------------+"
1357 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001358 delete [] counters;
Steve Blocka7e24c12009-10-30 11:49:00 +00001359 }
Ben Murdochc5610432016-08-08 18:44:38 +01001360
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001361 delete counters_file_;
1362 delete counter_map_;
1363#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001364}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001365
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001366
1367
1368static FILE* FOpen(const char* path, const char* mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001369#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001370 FILE* result;
1371 if (fopen_s(&result, path, mode) == 0) {
1372 return result;
1373 } else {
1374 return NULL;
1375 }
1376#else
1377 FILE* file = fopen(path, mode);
1378 if (file == NULL) return NULL;
1379 struct stat file_stat;
1380 if (fstat(fileno(file), &file_stat) != 0) return NULL;
1381 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
1382 if (is_regular_file) return file;
1383 fclose(file);
1384 return NULL;
1385#endif
1386}
Steve Blocka7e24c12009-10-30 11:49:00 +00001387
1388
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001389static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001390 FILE* file = FOpen(name, "rb");
Steve Blocka7e24c12009-10-30 11:49:00 +00001391 if (file == NULL) return NULL;
1392
1393 fseek(file, 0, SEEK_END);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001394 size_t size = ftell(file);
Steve Blocka7e24c12009-10-30 11:49:00 +00001395 rewind(file);
1396
1397 char* chars = new char[size + 1];
1398 chars[size] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001399 for (size_t i = 0; i < size;) {
1400 i += fread(&chars[i], 1, size - i, file);
1401 if (ferror(file)) {
1402 fclose(file);
1403 delete[] chars;
1404 return nullptr;
1405 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001406 }
1407 fclose(file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001408 *size_out = static_cast<int>(size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001409 return chars;
1410}
1411
1412
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001413struct DataAndPersistent {
1414 uint8_t* data;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001415 int byte_length;
1416 Global<ArrayBuffer> handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001417};
1418
1419
1420static void ReadBufferWeakCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001421 const v8::WeakCallbackInfo<DataAndPersistent>& data) {
1422 int byte_length = data.GetParameter()->byte_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001423 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
1424 -static_cast<intptr_t>(byte_length));
1425
1426 delete[] data.GetParameter()->data;
1427 data.GetParameter()->handle.Reset();
1428 delete data.GetParameter();
1429}
1430
1431
1432void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
1433 DCHECK(sizeof(char) == sizeof(uint8_t)); // NOLINT
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001434 String::Utf8Value filename(args[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001435 int length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001436 if (*filename == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001437 Throw(args.GetIsolate(), "Error loading file");
1438 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001439 }
1440
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001441 Isolate* isolate = args.GetIsolate();
1442 DataAndPersistent* data = new DataAndPersistent;
1443 data->data = reinterpret_cast<uint8_t*>(
1444 ReadChars(args.GetIsolate(), *filename, &length));
1445 if (data->data == NULL) {
1446 delete data;
1447 Throw(args.GetIsolate(), "Error reading file");
1448 return;
1449 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001450 data->byte_length = length;
1451 Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001452 data->handle.Reset(isolate, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001453 data->handle.SetWeak(data, ReadBufferWeakCallback,
1454 v8::WeakCallbackType::kParameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001455 data->handle.MarkIndependent();
1456 isolate->AdjustAmountOfExternalAllocatedMemory(length);
1457
1458 args.GetReturnValue().Set(buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00001459}
1460
1461
Steve Blocka7e24c12009-10-30 11:49:00 +00001462// Reads a file into a v8 string.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001463Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001464 int size = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001465 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001466 if (chars == NULL) return Local<String>();
1467 Local<String> result =
1468 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1469 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001470 delete[] chars;
1471 return result;
1472}
1473
1474
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001475void Shell::RunShell(Isolate* isolate) {
1476 HandleScope outer_scope(isolate);
1477 v8::Local<v8::Context> context =
1478 v8::Local<v8::Context>::New(isolate, evaluation_context_);
1479 v8::Context::Scope context_scope(context);
1480 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001481 Local<String> name =
1482 String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
1483 .ToLocalChecked();
1484 printf("V8 version %s\n", V8::GetVersion());
Steve Blocka7e24c12009-10-30 11:49:00 +00001485 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001486 HandleScope inner_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001487 printf("d8> ");
1488#if defined(__native_client__)
1489 // Native Client libc is used to being embedded in Chrome and
1490 // has trouble recognizing when to flush.
1491 fflush(stdout);
1492#endif
1493 Local<String> input = Shell::ReadFromStdin(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001494 if (input.IsEmpty()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001495 ExecuteString(isolate, input, name, true, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001496 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001497 printf("\n");
1498}
1499
1500
Ben Murdoch589d6972011-11-30 16:04:58 +00001501SourceGroup::~SourceGroup() {
1502#ifndef V8_SHARED
Ben Murdoch589d6972011-11-30 16:04:58 +00001503 delete thread_;
1504 thread_ = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001505#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001506}
Steve Blocka7e24c12009-10-30 11:49:00 +00001507
Steve Blocka7e24c12009-10-30 11:49:00 +00001508
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001509void SourceGroup::Execute(Isolate* isolate) {
1510 bool exception_was_thrown = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001511 for (int i = begin_offset_; i < end_offset_; ++i) {
1512 const char* arg = argv_[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001513 Shell::SourceType source_type = Shell::SCRIPT;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001514 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1515 // Execute argument given to -e option directly.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001516 HandleScope handle_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001517 Local<String> file_name =
1518 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1519 .ToLocalChecked();
1520 Local<String> source =
1521 String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
1522 .ToLocalChecked();
1523 Shell::options.script_executed = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001524 if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1525 exception_was_thrown = true;
1526 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001527 }
1528 ++i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001529 continue;
1530 } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
1531 // Treat the next file as a module.
1532 source_type = Shell::MODULE;
1533 arg = argv_[++i];
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001534 } else if (arg[0] == '-') {
1535 // Ignore other options. They have been parsed already.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001536 continue;
1537 }
1538
1539 // Use all other arguments as names of files to load and run.
1540 HandleScope handle_scope(isolate);
1541 Local<String> file_name =
1542 String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
1543 .ToLocalChecked();
1544 Local<String> source = ReadFile(isolate, arg);
1545 if (source.IsEmpty()) {
1546 printf("Error reading '%s'\n", arg);
1547 Shell::Exit(1);
1548 }
1549 Shell::options.script_executed = true;
1550 if (!Shell::ExecuteString(isolate, source, file_name, false, true,
1551 source_type)) {
1552 exception_was_thrown = true;
1553 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001554 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001555 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001556 if (exception_was_thrown != Shell::options.expected_to_throw) {
1557 Shell::Exit(1);
1558 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001559}
Steve Blocka7e24c12009-10-30 11:49:00 +00001560
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001561
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001562Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001563 int size;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001564 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001565 if (chars == NULL) return Local<String>();
1566 Local<String> result =
1567 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1568 .ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001569 delete[] chars;
1570 return result;
1571}
1572
1573
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001574#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001575base::Thread::Options SourceGroup::GetThreadOptions() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001576 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1577 // which is not enough to parse the big literal expressions used in tests.
1578 // The stack size should be at least StackGuard::kLimitSize + some
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001579 // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001580 return base::Thread::Options("IsolateThread", 2 * MB);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001581}
1582
1583
1584void SourceGroup::ExecuteInThread() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001585 Isolate::CreateParams create_params;
1586 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1587 Isolate* isolate = Isolate::New(create_params);
1588 for (int i = 0; i < Shell::options.stress_runs; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001589 next_semaphore_.Wait();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001590 {
1591 Isolate::Scope iscope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001592 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001593 HandleScope scope(isolate);
1594 PerIsolateData data(isolate);
1595 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1596 {
1597 Context::Scope cscope(context);
1598 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1599 Execute(isolate);
1600 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001601 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001602 Shell::CollectGarbage(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001603 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001604 done_semaphore_.Signal();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001605 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001606
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001607 isolate->Dispose();
1608}
1609
1610
1611void SourceGroup::StartExecuteInThread() {
1612 if (thread_ == NULL) {
1613 thread_ = new IsolateThread(this);
1614 thread_->Start();
1615 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001616 next_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001617}
1618
1619
1620void SourceGroup::WaitForThread() {
1621 if (thread_ == NULL) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001622 done_semaphore_.Wait();
1623}
1624
1625
1626void SourceGroup::JoinThread() {
1627 if (thread_ == NULL) return;
1628 thread_->Join();
1629}
1630
1631
1632SerializationData::~SerializationData() {
1633 // Any ArrayBuffer::Contents are owned by this SerializationData object if
1634 // ownership hasn't been transferred out via ReadArrayBufferContents.
1635 // SharedArrayBuffer::Contents may be used by multiple threads, so must be
1636 // cleaned up by the main thread in Shell::CleanupWorkers().
1637 for (int i = 0; i < array_buffer_contents_.length(); ++i) {
1638 ArrayBuffer::Contents& contents = array_buffer_contents_[i];
1639 if (contents.Data()) {
1640 Shell::array_buffer_allocator->Free(contents.Data(),
1641 contents.ByteLength());
1642 }
1643 }
1644}
1645
1646
1647void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); }
1648
1649
1650void SerializationData::WriteMemory(const void* p, int length) {
1651 if (length > 0) {
1652 i::Vector<uint8_t> block = data_.AddBlock(0, length);
1653 memcpy(&block[0], p, length);
1654 }
1655}
1656
1657
1658void SerializationData::WriteArrayBufferContents(
1659 const ArrayBuffer::Contents& contents) {
1660 array_buffer_contents_.Add(contents);
1661 WriteTag(kSerializationTagTransferredArrayBuffer);
1662 int index = array_buffer_contents_.length() - 1;
1663 Write(index);
1664}
1665
1666
1667void SerializationData::WriteSharedArrayBufferContents(
1668 const SharedArrayBuffer::Contents& contents) {
1669 shared_array_buffer_contents_.Add(contents);
1670 WriteTag(kSerializationTagTransferredSharedArrayBuffer);
1671 int index = shared_array_buffer_contents_.length() - 1;
1672 Write(index);
1673}
1674
1675
1676SerializationTag SerializationData::ReadTag(int* offset) const {
1677 return static_cast<SerializationTag>(Read<uint8_t>(offset));
1678}
1679
1680
1681void SerializationData::ReadMemory(void* p, int length, int* offset) const {
1682 if (length > 0) {
1683 memcpy(p, &data_[*offset], length);
1684 (*offset) += length;
1685 }
1686}
1687
1688
1689void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents,
1690 int* offset) const {
1691 int index = Read<int>(offset);
1692 DCHECK(index < array_buffer_contents_.length());
1693 *contents = array_buffer_contents_[index];
1694 // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter
1695 // our copy so it won't be double-free'd when this SerializationData is
1696 // destroyed.
1697 array_buffer_contents_[index] = ArrayBuffer::Contents();
1698}
1699
1700
1701void SerializationData::ReadSharedArrayBufferContents(
1702 SharedArrayBuffer::Contents* contents, int* offset) const {
1703 int index = Read<int>(offset);
1704 DCHECK(index < shared_array_buffer_contents_.length());
1705 *contents = shared_array_buffer_contents_[index];
1706}
1707
1708
1709void SerializationDataQueue::Enqueue(SerializationData* data) {
1710 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1711 data_.Add(data);
1712}
1713
1714
1715bool SerializationDataQueue::Dequeue(SerializationData** data) {
1716 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1717 *data = NULL;
1718 if (data_.is_empty()) return false;
1719 *data = data_.Remove(0);
1720 return true;
1721}
1722
1723
1724bool SerializationDataQueue::IsEmpty() {
1725 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1726 return data_.is_empty();
1727}
1728
1729
1730void SerializationDataQueue::Clear() {
1731 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1732 for (int i = 0; i < data_.length(); ++i) {
1733 delete data_[i];
1734 }
1735 data_.Clear();
1736}
1737
1738
1739Worker::Worker()
1740 : in_semaphore_(0),
1741 out_semaphore_(0),
1742 thread_(NULL),
1743 script_(NULL),
1744 running_(false) {}
1745
1746
1747Worker::~Worker() {
1748 delete thread_;
1749 thread_ = NULL;
1750 delete[] script_;
1751 script_ = NULL;
1752 in_queue_.Clear();
1753 out_queue_.Clear();
1754}
1755
1756
1757void Worker::StartExecuteInThread(const char* script) {
1758 running_ = true;
1759 script_ = i::StrDup(script);
1760 thread_ = new WorkerThread(this);
1761 thread_->Start();
1762}
1763
1764
1765void Worker::PostMessage(SerializationData* data) {
1766 in_queue_.Enqueue(data);
1767 in_semaphore_.Signal();
1768}
1769
1770
1771SerializationData* Worker::GetMessage() {
1772 SerializationData* data = NULL;
1773 while (!out_queue_.Dequeue(&data)) {
1774 // If the worker is no longer running, and there are no messages in the
1775 // queue, don't expect any more messages from it.
1776 if (!base::NoBarrier_Load(&running_)) break;
1777 out_semaphore_.Wait();
1778 }
1779 return data;
1780}
1781
1782
1783void Worker::Terminate() {
1784 base::NoBarrier_Store(&running_, false);
1785 // Post NULL to wake the Worker thread message loop, and tell it to stop
1786 // running.
1787 PostMessage(NULL);
1788}
1789
1790
1791void Worker::WaitForThread() {
1792 Terminate();
1793 thread_->Join();
1794}
1795
1796
1797void Worker::ExecuteInThread() {
1798 Isolate::CreateParams create_params;
1799 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1800 Isolate* isolate = Isolate::New(create_params);
1801 {
1802 Isolate::Scope iscope(isolate);
1803 {
1804 HandleScope scope(isolate);
1805 PerIsolateData data(isolate);
1806 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1807 {
1808 Context::Scope cscope(context);
1809 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1810
1811 Local<Object> global = context->Global();
1812 Local<Value> this_value = External::New(isolate, this);
1813 Local<FunctionTemplate> postmessage_fun_template =
1814 FunctionTemplate::New(isolate, PostMessageOut, this_value);
1815
1816 Local<Function> postmessage_fun;
1817 if (postmessage_fun_template->GetFunction(context)
1818 .ToLocal(&postmessage_fun)) {
1819 global->Set(context, String::NewFromUtf8(isolate, "postMessage",
1820 NewStringType::kNormal)
1821 .ToLocalChecked(),
1822 postmessage_fun).FromJust();
1823 }
1824
1825 // First run the script
1826 Local<String> file_name =
1827 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1828 .ToLocalChecked();
1829 Local<String> source =
1830 String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
1831 .ToLocalChecked();
1832 if (Shell::ExecuteString(isolate, source, file_name, false, true)) {
1833 // Get the message handler
1834 Local<Value> onmessage =
1835 global->Get(context, String::NewFromUtf8(isolate, "onmessage",
1836 NewStringType::kNormal)
1837 .ToLocalChecked()).ToLocalChecked();
1838 if (onmessage->IsFunction()) {
1839 Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
1840 // Now wait for messages
1841 while (true) {
1842 in_semaphore_.Wait();
1843 SerializationData* data;
1844 if (!in_queue_.Dequeue(&data)) continue;
1845 if (data == NULL) {
1846 break;
1847 }
1848 int offset = 0;
1849 Local<Value> data_value;
1850 if (Shell::DeserializeValue(isolate, *data, &offset)
1851 .ToLocal(&data_value)) {
1852 Local<Value> argv[] = {data_value};
1853 (void)onmessage_fun->Call(context, global, 1, argv);
1854 }
1855 delete data;
1856 }
1857 }
1858 }
1859 }
1860 }
1861 Shell::CollectGarbage(isolate);
1862 }
1863 isolate->Dispose();
1864
1865 // Post NULL to wake the thread waiting on GetMessage() if there is one.
1866 out_queue_.Enqueue(NULL);
1867 out_semaphore_.Signal();
1868}
1869
1870
1871void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
1872 Isolate* isolate = args.GetIsolate();
1873 HandleScope handle_scope(isolate);
1874
1875 if (args.Length() < 1) {
1876 Throw(isolate, "Invalid argument");
1877 return;
1878 }
1879
1880 Local<Value> message = args[0];
1881
1882 // TODO(binji): Allow transferring from worker to main thread?
1883 Shell::ObjectList to_transfer;
1884
1885 Shell::ObjectList seen_objects;
1886 SerializationData* data = new SerializationData;
1887 if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects,
1888 data)) {
1889 DCHECK(args.Data()->IsExternal());
1890 Local<External> this_value = Local<External>::Cast(args.Data());
1891 Worker* worker = static_cast<Worker*>(this_value->Value());
1892 worker->out_queue_.Enqueue(data);
1893 worker->out_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001894 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001895 delete data;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001896 }
1897}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001898#endif // !V8_SHARED
1899
1900
1901void SetFlagsFromString(const char* flags) {
1902 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
1903}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001904
1905
1906bool Shell::SetOptions(int argc, char* argv[]) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001907 bool logfile_per_isolate = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001908 for (int i = 0; i < argc; i++) {
1909 if (strcmp(argv[i], "--stress-opt") == 0) {
1910 options.stress_opt = true;
1911 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001912 } else if (strcmp(argv[i], "--nostress-opt") == 0) {
1913 options.stress_opt = false;
1914 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001915 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1916 options.stress_deopt = true;
1917 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918 } else if (strcmp(argv[i], "--mock-arraybuffer-allocator") == 0) {
1919 options.mock_arraybuffer_allocator = true;
1920 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001921 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1922 // No support for stressing if we can't use --always-opt.
1923 options.stress_opt = false;
1924 options.stress_deopt = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001925 } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
1926 logfile_per_isolate = true;
1927 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001928 } else if (strcmp(argv[i], "--shell") == 0) {
1929 options.interactive_shell = true;
1930 argv[i] = NULL;
1931 } else if (strcmp(argv[i], "--test") == 0) {
1932 options.test_shell = true;
1933 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001934 } else if (strcmp(argv[i], "--notest") == 0 ||
1935 strcmp(argv[i], "--no-test") == 0) {
1936 options.test_shell = false;
1937 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001938 } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
1939 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001940 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001941 } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
1942 options.invoke_weak_callbacks = true;
1943 // TODO(jochen) See issue 3351
1944 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001945 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001946 } else if (strcmp(argv[i], "--omit-quit") == 0) {
1947 options.omit_quit = true;
1948 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001949 } else if (strcmp(argv[i], "-f") == 0) {
1950 // Ignore any -f flags for compatibility with other stand-alone
1951 // JavaScript engines.
1952 continue;
1953 } else if (strcmp(argv[i], "--isolate") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001954#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001955 printf("D8 with shared library does not support multi-threading\n");
1956 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001957#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001958 options.num_isolates++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001959 } else if (strcmp(argv[i], "--dump-heap-constants") == 0) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001960#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001961 printf("D8 with shared library does not support constant dumping\n");
Ben Murdoch589d6972011-11-30 16:04:58 +00001962 return false;
1963#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001964 options.dump_heap_constants = true;
1965 argv[i] = NULL;
Ben Murdoch589d6972011-11-30 16:04:58 +00001966#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001967 } else if (strcmp(argv[i], "--throws") == 0) {
1968 options.expected_to_throw = true;
1969 argv[i] = NULL;
1970 } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
1971 options.icu_data_file = argv[i] + 16;
1972 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001973#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001974 } else if (strcmp(argv[i], "--dump-counters") == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001975 printf("D8 with shared library does not include counters\n");
1976 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001977#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001978#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1979 } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
1980 options.natives_blob = argv[i] + 15;
1981 argv[i] = NULL;
1982 } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
1983 options.snapshot_blob = argv[i] + 16;
1984 argv[i] = NULL;
1985#endif // V8_USE_EXTERNAL_STARTUP_DATA
1986 } else if (strcmp(argv[i], "--cache") == 0 ||
1987 strncmp(argv[i], "--cache=", 8) == 0) {
1988 const char* value = argv[i] + 7;
1989 if (!*value || strncmp(value, "=code", 6) == 0) {
1990 options.compile_options = v8::ScriptCompiler::kProduceCodeCache;
1991 } else if (strncmp(value, "=parse", 7) == 0) {
1992 options.compile_options = v8::ScriptCompiler::kProduceParserCache;
1993 } else if (strncmp(value, "=none", 6) == 0) {
1994 options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
1995 } else {
1996 printf("Unknown option to --cache.\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001997 return false;
1998 }
1999 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002000 }
2001 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002002
2003 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
2004
Ben Murdoch589d6972011-11-30 16:04:58 +00002005 // Set up isolated source groups.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002006 options.isolate_sources = new SourceGroup[options.num_isolates];
2007 SourceGroup* current = options.isolate_sources;
2008 current->Begin(argv, 1);
2009 for (int i = 1; i < argc; i++) {
2010 const char* str = argv[i];
2011 if (strcmp(str, "--isolate") == 0) {
2012 current->End(i);
2013 current++;
2014 current->Begin(argv, i + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002015 } else if (strcmp(str, "--module") == 0) {
2016 // Pass on to SourceGroup, which understands this option.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002017 } else if (strncmp(argv[i], "--", 2) == 0) {
2018 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002019 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
2020 options.script_executed = true;
2021 } else if (strncmp(str, "-", 1) != 0) {
2022 // Not a flag, so it must be a script to execute.
2023 options.script_executed = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002024 }
2025 }
2026 current->End(argc);
2027
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002028 if (!logfile_per_isolate && options.num_isolates) {
2029 SetFlagsFromString("--nologfile_per_isolate");
2030 }
2031
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002032 return true;
2033}
2034
2035
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002036int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002037#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002038 for (int i = 1; i < options.num_isolates; ++i) {
2039 options.isolate_sources[i].StartExecuteInThread();
2040 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002041#endif // !V8_SHARED
2042 {
2043 HandleScope scope(isolate);
2044 Local<Context> context = CreateEvaluationContext(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002045 if (last_run && options.use_interactive_shell()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002046 // Keep using the same context in the interactive shell.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002047 evaluation_context_.Reset(isolate, context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002048 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002049 {
2050 Context::Scope cscope(context);
2051 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2052 options.isolate_sources[0].Execute(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002053 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002054 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002055 CollectGarbage(isolate);
2056#ifndef V8_SHARED
2057 for (int i = 1; i < options.num_isolates; ++i) {
2058 if (last_run) {
2059 options.isolate_sources[i].JoinThread();
2060 } else {
2061 options.isolate_sources[i].WaitForThread();
2062 }
2063 }
2064 CleanupWorkers();
2065#endif // !V8_SHARED
2066 return 0;
2067}
2068
2069
2070void Shell::CollectGarbage(Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002071 if (options.send_idle_notification) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002072 const double kLongIdlePauseInSeconds = 1.0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002073 isolate->ContextDisposedNotification();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002074 isolate->IdleNotificationDeadline(
2075 g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002076 }
2077 if (options.invoke_weak_callbacks) {
2078 // By sending a low memory notifications, we will try hard to collect all
2079 // garbage and will therefore also invoke all weak callbacks of actually
2080 // unreachable persistent handles.
2081 isolate->LowMemoryNotification();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002082 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002083}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002084
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002085
2086void Shell::EmptyMessageQueues(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002087#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002088 if (!i::FLAG_verify_predictable) {
2089#endif
2090 while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue;
2091#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002092 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002093#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00002094}
2095
2096
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002097#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002098bool Shell::SerializeValue(Isolate* isolate, Local<Value> value,
2099 const ObjectList& to_transfer,
2100 ObjectList* seen_objects,
2101 SerializationData* out_data) {
2102 DCHECK(out_data);
2103 Local<Context> context = isolate->GetCurrentContext();
2104
2105 if (value->IsUndefined()) {
2106 out_data->WriteTag(kSerializationTagUndefined);
2107 } else if (value->IsNull()) {
2108 out_data->WriteTag(kSerializationTagNull);
2109 } else if (value->IsTrue()) {
2110 out_data->WriteTag(kSerializationTagTrue);
2111 } else if (value->IsFalse()) {
2112 out_data->WriteTag(kSerializationTagFalse);
2113 } else if (value->IsNumber()) {
2114 Local<Number> num = Local<Number>::Cast(value);
2115 double value = num->Value();
2116 out_data->WriteTag(kSerializationTagNumber);
2117 out_data->Write(value);
2118 } else if (value->IsString()) {
2119 v8::String::Utf8Value str(value);
2120 out_data->WriteTag(kSerializationTagString);
2121 out_data->Write(str.length());
2122 out_data->WriteMemory(*str, str.length());
2123 } else if (value->IsArray()) {
2124 Local<Array> array = Local<Array>::Cast(value);
2125 if (FindInObjectList(array, *seen_objects)) {
2126 Throw(isolate, "Duplicated arrays not supported");
2127 return false;
2128 }
2129 seen_objects->Add(array);
2130 out_data->WriteTag(kSerializationTagArray);
2131 uint32_t length = array->Length();
2132 out_data->Write(length);
2133 for (uint32_t i = 0; i < length; ++i) {
2134 Local<Value> element_value;
2135 if (array->Get(context, i).ToLocal(&element_value)) {
2136 if (!SerializeValue(isolate, element_value, to_transfer, seen_objects,
2137 out_data))
2138 return false;
2139 } else {
2140 Throw(isolate, "Failed to serialize array element.");
2141 return false;
2142 }
2143 }
2144 } else if (value->IsArrayBuffer()) {
2145 Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value);
2146 if (FindInObjectList(array_buffer, *seen_objects)) {
2147 Throw(isolate, "Duplicated array buffers not supported");
2148 return false;
2149 }
2150 seen_objects->Add(array_buffer);
2151 if (FindInObjectList(array_buffer, to_transfer)) {
2152 // Transfer ArrayBuffer
2153 if (!array_buffer->IsNeuterable()) {
2154 Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer");
2155 return false;
2156 }
2157
2158 ArrayBuffer::Contents contents = array_buffer->IsExternal()
2159 ? array_buffer->GetContents()
2160 : array_buffer->Externalize();
2161 array_buffer->Neuter();
2162 out_data->WriteArrayBufferContents(contents);
2163 } else {
2164 ArrayBuffer::Contents contents = array_buffer->GetContents();
2165 // Clone ArrayBuffer
2166 if (contents.ByteLength() > i::kMaxInt) {
2167 Throw(isolate, "ArrayBuffer is too big to clone");
2168 return false;
2169 }
2170
2171 int32_t byte_length = static_cast<int32_t>(contents.ByteLength());
2172 out_data->WriteTag(kSerializationTagArrayBuffer);
2173 out_data->Write(byte_length);
2174 out_data->WriteMemory(contents.Data(), byte_length);
2175 }
2176 } else if (value->IsSharedArrayBuffer()) {
2177 Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value);
2178 if (FindInObjectList(sab, *seen_objects)) {
2179 Throw(isolate, "Duplicated shared array buffers not supported");
2180 return false;
2181 }
2182 seen_objects->Add(sab);
2183 if (!FindInObjectList(sab, to_transfer)) {
2184 Throw(isolate, "SharedArrayBuffer must be transferred");
2185 return false;
2186 }
2187
2188 SharedArrayBuffer::Contents contents;
2189 if (sab->IsExternal()) {
2190 contents = sab->GetContents();
2191 } else {
2192 contents = sab->Externalize();
2193 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2194 externalized_shared_contents_.Add(contents);
2195 }
2196 out_data->WriteSharedArrayBufferContents(contents);
2197 } else if (value->IsObject()) {
2198 Local<Object> object = Local<Object>::Cast(value);
2199 if (FindInObjectList(object, *seen_objects)) {
2200 Throw(isolate, "Duplicated objects not supported");
2201 return false;
2202 }
2203 seen_objects->Add(object);
2204 Local<Array> property_names;
2205 if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
2206 Throw(isolate, "Unable to get property names");
2207 return false;
2208 }
2209
2210 uint32_t length = property_names->Length();
2211 out_data->WriteTag(kSerializationTagObject);
2212 out_data->Write(length);
2213 for (uint32_t i = 0; i < length; ++i) {
2214 Local<Value> name;
2215 Local<Value> property_value;
2216 if (property_names->Get(context, i).ToLocal(&name) &&
2217 object->Get(context, name).ToLocal(&property_value)) {
2218 if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data))
2219 return false;
2220 if (!SerializeValue(isolate, property_value, to_transfer, seen_objects,
2221 out_data))
2222 return false;
2223 } else {
2224 Throw(isolate, "Failed to serialize property.");
2225 return false;
2226 }
2227 }
2228 } else {
2229 Throw(isolate, "Don't know how to serialize object");
2230 return false;
2231 }
2232
2233 return true;
2234}
2235
2236
2237MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
2238 const SerializationData& data,
2239 int* offset) {
2240 DCHECK(offset);
2241 EscapableHandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002242 Local<Value> result;
2243 SerializationTag tag = data.ReadTag(offset);
2244
2245 switch (tag) {
2246 case kSerializationTagUndefined:
2247 result = Undefined(isolate);
2248 break;
2249 case kSerializationTagNull:
2250 result = Null(isolate);
2251 break;
2252 case kSerializationTagTrue:
2253 result = True(isolate);
2254 break;
2255 case kSerializationTagFalse:
2256 result = False(isolate);
2257 break;
2258 case kSerializationTagNumber:
2259 result = Number::New(isolate, data.Read<double>(offset));
2260 break;
2261 case kSerializationTagString: {
2262 int length = data.Read<int>(offset);
2263 CHECK(length >= 0);
2264 std::vector<char> buffer(length + 1); // + 1 so it is never empty.
2265 data.ReadMemory(&buffer[0], length, offset);
2266 MaybeLocal<String> str =
2267 String::NewFromUtf8(isolate, &buffer[0], NewStringType::kNormal,
2268 length).ToLocalChecked();
2269 if (!str.IsEmpty()) result = str.ToLocalChecked();
2270 break;
2271 }
2272 case kSerializationTagArray: {
2273 uint32_t length = data.Read<uint32_t>(offset);
2274 Local<Array> array = Array::New(isolate, length);
2275 for (uint32_t i = 0; i < length; ++i) {
2276 Local<Value> element_value;
2277 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value));
2278 array->Set(isolate->GetCurrentContext(), i, element_value).FromJust();
2279 }
2280 result = array;
2281 break;
2282 }
2283 case kSerializationTagObject: {
2284 int length = data.Read<int>(offset);
2285 Local<Object> object = Object::New(isolate);
2286 for (int i = 0; i < length; ++i) {
2287 Local<Value> property_name;
2288 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name));
2289 Local<Value> property_value;
2290 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value));
2291 object->Set(isolate->GetCurrentContext(), property_name, property_value)
2292 .FromJust();
2293 }
2294 result = object;
2295 break;
2296 }
2297 case kSerializationTagArrayBuffer: {
2298 int32_t byte_length = data.Read<int32_t>(offset);
2299 Local<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length);
2300 ArrayBuffer::Contents contents = array_buffer->GetContents();
2301 DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength());
2302 data.ReadMemory(contents.Data(), byte_length, offset);
2303 result = array_buffer;
2304 break;
2305 }
2306 case kSerializationTagTransferredArrayBuffer: {
2307 ArrayBuffer::Contents contents;
2308 data.ReadArrayBufferContents(&contents, offset);
2309 result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(),
2310 ArrayBufferCreationMode::kInternalized);
2311 break;
2312 }
2313 case kSerializationTagTransferredSharedArrayBuffer: {
2314 SharedArrayBuffer::Contents contents;
2315 data.ReadSharedArrayBufferContents(&contents, offset);
2316 result = SharedArrayBuffer::New(isolate, contents.Data(),
2317 contents.ByteLength());
2318 break;
2319 }
2320 default:
2321 UNREACHABLE();
2322 }
2323
2324 return scope.Escape(result);
2325}
2326
2327
2328void Shell::CleanupWorkers() {
2329 // Make a copy of workers_, because we don't want to call Worker::Terminate
2330 // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
2331 // create a new Worker, it would deadlock.
2332 i::List<Worker*> workers_copy;
2333 {
2334 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2335 allow_new_workers_ = false;
2336 workers_copy.AddAll(workers_);
2337 workers_.Clear();
2338 }
2339
2340 for (int i = 0; i < workers_copy.length(); ++i) {
2341 Worker* worker = workers_copy[i];
2342 worker->WaitForThread();
2343 delete worker;
2344 }
2345
2346 // Now that all workers are terminated, we can re-enable Worker creation.
2347 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2348 allow_new_workers_ = true;
2349
2350 for (int i = 0; i < externalized_shared_contents_.length(); ++i) {
2351 const SharedArrayBuffer::Contents& contents =
2352 externalized_shared_contents_[i];
2353 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
2354 }
2355 externalized_shared_contents_.Clear();
2356}
2357
2358
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002359static void DumpHeapConstants(i::Isolate* isolate) {
2360 i::Heap* heap = isolate->heap();
2361
2362 // Dump the INSTANCE_TYPES table to the console.
2363 printf("# List of known V8 instance types.\n");
2364#define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T);
2365 printf("INSTANCE_TYPES = {\n");
2366 INSTANCE_TYPE_LIST(DUMP_TYPE)
2367 printf("}\n");
2368#undef DUMP_TYPE
2369
2370 // Dump the KNOWN_MAP table to the console.
2371 printf("\n# List of known V8 maps.\n");
2372#define ROOT_LIST_CASE(type, name, camel_name) \
2373 if (n == NULL && o == heap->name()) n = #camel_name;
2374#define STRUCT_LIST_CASE(upper_name, camel_name, name) \
2375 if (n == NULL && o == heap->name##_map()) n = #camel_name "Map";
2376 i::HeapObjectIterator it(heap->map_space());
2377 printf("KNOWN_MAPS = {\n");
2378 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2379 i::Map* m = i::Map::cast(o);
2380 const char* n = NULL;
2381 intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
2382 int t = m->instance_type();
2383 ROOT_LIST(ROOT_LIST_CASE)
2384 STRUCT_LIST(STRUCT_LIST_CASE)
2385 if (n == NULL) continue;
2386 printf(" 0x%05" V8PRIxPTR ": (%d, \"%s\"),\n", p, t, n);
2387 }
2388 printf("}\n");
2389#undef STRUCT_LIST_CASE
2390#undef ROOT_LIST_CASE
2391
2392 // Dump the KNOWN_OBJECTS table to the console.
2393 printf("\n# List of known V8 objects.\n");
2394#define ROOT_LIST_CASE(type, name, camel_name) \
2395 if (n == NULL && o == heap->name()) n = #camel_name;
2396 i::OldSpaces spit(heap);
2397 printf("KNOWN_OBJECTS = {\n");
2398 for (i::PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
2399 i::HeapObjectIterator it(s);
2400 const char* sname = AllocationSpaceName(s->identity());
2401 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2402 const char* n = NULL;
2403 intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
2404 ROOT_LIST(ROOT_LIST_CASE)
2405 if (n == NULL) continue;
2406 printf(" (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", sname, p, n);
2407 }
2408 }
2409 printf("}\n");
2410#undef ROOT_LIST_CASE
2411}
2412#endif // !V8_SHARED
2413
2414
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002415int Shell::Main(int argc, char* argv[]) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002416#if (defined(_WIN32) || defined(_WIN64))
2417 UINT new_flags =
2418 SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
2419 UINT existing_flags = SetErrorMode(new_flags);
2420 SetErrorMode(existing_flags | new_flags);
2421#if defined(_MSC_VER)
2422 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2423 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
2424 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2425 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
2426 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2427 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
2428 _set_error_mode(_OUT_TO_STDERR);
2429#endif // defined(_MSC_VER)
2430#endif // defined(_WIN32) || defined(_WIN64)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002431 if (!SetOptions(argc, argv)) return 1;
Ben Murdoch61f157c2016-09-16 13:49:30 +01002432 v8::V8::InitializeICUDefaultLocation(argv[0], options.icu_data_file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002433#ifndef V8_SHARED
2434 g_platform = i::FLAG_verify_predictable
2435 ? new PredictablePlatform()
2436 : v8::platform::CreateDefaultPlatform();
2437#else
2438 g_platform = v8::platform::CreateDefaultPlatform();
2439#endif // !V8_SHARED
2440
2441 v8::V8::InitializePlatform(g_platform);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002442 v8::V8::Initialize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002443 if (options.natives_blob || options.snapshot_blob) {
2444 v8::V8::InitializeExternalStartupData(options.natives_blob,
2445 options.snapshot_blob);
2446 } else {
2447 v8::V8::InitializeExternalStartupData(argv[0]);
2448 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002449 SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002450 SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002451 SetFlagsFromString("--redirect-code-traces-to=code.asm");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002452 int result = 0;
2453 Isolate::CreateParams create_params;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002454 ShellArrayBufferAllocator shell_array_buffer_allocator;
2455 MockArrayBufferAllocator mock_arraybuffer_allocator;
2456 if (options.mock_arraybuffer_allocator) {
2457 Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
2458 } else {
2459 Shell::array_buffer_allocator = &shell_array_buffer_allocator;
2460 }
2461 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002462#ifdef ENABLE_VTUNE_JIT_INTERFACE
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002463 create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002464#endif
2465#ifndef V8_SHARED
2466 create_params.constraints.ConfigureDefaults(
2467 base::SysInfo::AmountOfPhysicalMemory(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002468 base::SysInfo::AmountOfVirtualMemory());
2469
2470 Shell::counter_map_ = new CounterMap();
2471 if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
2472 create_params.counter_lookup_callback = LookupCounter;
2473 create_params.create_histogram_callback = CreateHistogram;
2474 create_params.add_histogram_sample_callback = AddHistogramSample;
2475 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002476#endif
2477 Isolate* isolate = Isolate::New(create_params);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002478 {
2479 Isolate::Scope scope(isolate);
2480 Initialize(isolate);
2481 PerIsolateData data(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002482
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002483#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002484 if (options.dump_heap_constants) {
2485 DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate));
2486 return 0;
2487 }
2488#endif
2489
2490 if (options.stress_opt || options.stress_deopt) {
2491 Testing::SetStressRunType(options.stress_opt
2492 ? Testing::kStressTypeOpt
2493 : Testing::kStressTypeDeopt);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002494 options.stress_runs = Testing::GetStressRuns();
2495 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2496 printf("============ Stress %d/%d ============\n", i + 1,
2497 options.stress_runs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002498 Testing::PrepareStressRun(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002499 bool last_run = i == options.stress_runs - 1;
2500 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002501 }
2502 printf("======== Full Deoptimization =======\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002503 Testing::DeoptimizeAll(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002504#if !defined(V8_SHARED)
2505 } else if (i::FLAG_stress_runs > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002506 options.stress_runs = i::FLAG_stress_runs;
2507 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2508 printf("============ Run %d/%d ============\n", i + 1,
2509 options.stress_runs);
2510 bool last_run = i == options.stress_runs - 1;
2511 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002512 }
2513#endif
2514 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002515 bool last_run = true;
2516 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002517 }
2518
2519 // Run interactive shell if explicitly requested or if no script has been
2520 // executed, but never on --test
2521 if (options.use_interactive_shell()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002522 RunShell(isolate);
2523 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002524
Ben Murdochc5610432016-08-08 18:44:38 +01002525#ifndef V8_SHARED
2526 if (i::FLAG_ignition && i::FLAG_trace_ignition_dispatches &&
2527 i::FLAG_trace_ignition_dispatches_output_file != nullptr) {
2528 WriteIgnitionDispatchCountersFile(isolate);
2529 }
2530#endif
2531
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002532 // Shut down contexts and collect garbage.
2533 evaluation_context_.Reset();
2534#ifndef V8_SHARED
Ben Murdochda12d292016-06-02 14:46:10 +01002535 stringify_function_.Reset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002536#endif // !V8_SHARED
2537 CollectGarbage(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002538 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002539 OnExit(isolate);
2540#ifndef V8_SHARED
2541 // Dump basic block profiling data.
2542 if (i::BasicBlockProfiler* profiler =
2543 reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
2544 i::OFStream os(stdout);
2545 os << *profiler;
2546 }
2547#endif // !V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002548 isolate->Dispose();
2549 V8::Dispose();
2550 V8::ShutdownPlatform();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002551 delete g_platform;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002552
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002553 return result;
2554}
2555
Steve Blocka7e24c12009-10-30 11:49:00 +00002556} // namespace v8
2557
2558
Ben Murdoch257744e2011-11-30 15:57:28 +00002559#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +00002560int main(int argc, char* argv[]) {
2561 return v8::Shell::Main(argc, argv);
2562}
Ben Murdoch257744e2011-11-30 15:57:28 +00002563#endif