blob: c58c172640edfd31fe0c2e876c8ab98f739cd869 [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 Murdoch4a90d5f2016-03-22 12:00:34 +000022#include <vector>
Ben Murdochb8a8cc12014-11-26 15:28:44 +000023#endif // !V8_SHARED
24
25#ifdef V8_SHARED
26#include "include/v8-testing.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000027#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +000028
Ben Murdochb8a8cc12014-11-26 15:28:44 +000029#if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE)
30#include "src/gdb-jit.h"
31#endif
32
33#ifdef ENABLE_VTUNE_JIT_INTERFACE
34#include "src/third_party/vtune/v8-vtune.h"
35#endif
36
37#include "src/d8.h"
38
39#include "include/libplatform/libplatform.h"
40#ifndef V8_SHARED
41#include "src/api.h"
42#include "src/base/cpu.h"
43#include "src/base/logging.h"
44#include "src/base/platform/platform.h"
45#include "src/base/sys-info.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040046#include "src/basic-block-profiler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047#include "src/snapshot/natives.h"
48#include "src/utils.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000049#include "src/v8.h"
50#endif // !V8_SHARED
51
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000052#if !defined(_WIN32) && !defined(_WIN64)
53#include <unistd.h> // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054#else
55#include <windows.h> // NOLINT
56#if defined(_MSC_VER)
57#include <crtdbg.h> // NOLINT
58#endif // defined(_MSC_VER)
59#endif // !defined(_WIN32) && !defined(_WIN64)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000060
Ben Murdochb8a8cc12014-11-26 15:28:44 +000061#ifndef DCHECK
62#define DCHECK(condition) assert(condition)
Ben Murdoch69a99ed2011-11-30 16:03:39 +000063#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000064
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065#ifndef CHECK
66#define CHECK(condition) assert(condition)
67#endif
68
Steve Blocka7e24c12009-10-30 11:49:00 +000069namespace v8 {
70
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000071namespace {
Steve Blocka7e24c12009-10-30 11:49:00 +000072
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073const int MB = 1024 * 1024;
74#ifndef V8_SHARED
75const int kMaxWorkers = 50;
76#endif
77
78
79class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
80 public:
81 virtual void* Allocate(size_t length) {
82 void* data = AllocateUninitialized(length);
83 return data == NULL ? data : memset(data, 0, length);
84 }
85 virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
86 virtual void Free(void* data, size_t) { free(data); }
87};
88
89
90class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
91 public:
92 void* Allocate(size_t length) override {
93 size_t actual_length = length > 10 * MB ? 1 : length;
94 void* data = AllocateUninitialized(actual_length);
95 return data == NULL ? data : memset(data, 0, actual_length);
96 }
97 void* AllocateUninitialized(size_t length) override {
98 return length > 10 * MB ? malloc(1) : malloc(length);
99 }
100 void Free(void* p, size_t) override { free(p); }
101};
102
103
104#ifndef V8_SHARED
105// Predictable v8::Platform implementation. All background and foreground
106// tasks are run immediately, delayed tasks are not executed at all.
107class PredictablePlatform : public Platform {
108 public:
109 PredictablePlatform() {}
110
111 void CallOnBackgroundThread(Task* task,
112 ExpectedRuntime expected_runtime) override {
113 task->Run();
114 delete task;
115 }
116
117 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
118 task->Run();
119 delete task;
120 }
121
122 void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
123 double delay_in_seconds) override {
124 delete task;
125 }
126
127 void CallIdleOnForegroundThread(v8::Isolate* isolate,
128 IdleTask* task) override {
129 UNREACHABLE();
130 }
131
132 bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
133
134 double MonotonicallyIncreasingTime() override {
135 return synthetic_time_in_sec_ += 0.00001;
136 }
137
138 uint64_t AddTraceEvent(char phase, const uint8_t* categoryEnabledFlag,
139 const char* name, uint64_t id, uint64_t bind_id,
140 int numArgs, const char** argNames,
141 const uint8_t* argTypes, const uint64_t* argValues,
142 unsigned int flags) override {
143 return 0;
144 }
145
146 void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
147 const char* name, uint64_t handle) override {}
148
149 const uint8_t* GetCategoryGroupEnabled(const char* name) override {
150 static uint8_t no = 0;
151 return &no;
152 }
153
154 const char* GetCategoryGroupName(
155 const uint8_t* categoryEnabledFlag) override {
156 static const char* dummy = "dummy";
157 return dummy;
158 }
159
160 private:
161 double synthetic_time_in_sec_ = 0.0;
162
163 DISALLOW_COPY_AND_ASSIGN(PredictablePlatform);
164};
165#endif // !V8_SHARED
166
167
168v8::Platform* g_platform = NULL;
169
170
171static Local<Value> Throw(Isolate* isolate, const char* message) {
172 return isolate->ThrowException(
173 String::NewFromUtf8(isolate, message, NewStringType::kNormal)
174 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000175}
176
177
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000178#ifndef V8_SHARED
179bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) {
180 for (int i = 0; i < list.length(); ++i) {
181 if (list[i]->StrictEquals(object)) {
182 return true;
183 }
184 }
185 return false;
186}
187
188
189Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
190 if (object->InternalFieldCount() != 1) {
191 Throw(isolate, "this is not a Worker");
192 return NULL;
193 }
194
195 Worker* worker =
196 static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
197 if (worker == NULL) {
198 Throw(isolate, "Worker is defunct because main thread is terminating");
199 return NULL;
200 }
201
202 return worker;
203}
204#endif // !V8_SHARED
205
206
207} // namespace
208
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000209
210class PerIsolateData {
211 public:
212 explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
213 HandleScope scope(isolate);
214 isolate->SetData(0, this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000215 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000216
217 ~PerIsolateData() {
218 isolate_->SetData(0, NULL); // Not really needed, just to be sure...
219 }
220
221 inline static PerIsolateData* Get(Isolate* isolate) {
222 return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
223 }
224
225 class RealmScope {
226 public:
227 explicit RealmScope(PerIsolateData* data);
228 ~RealmScope();
229 private:
230 PerIsolateData* data_;
231 };
232
233 private:
234 friend class Shell;
235 friend class RealmScope;
236 Isolate* isolate_;
237 int realm_count_;
238 int realm_current_;
239 int realm_switch_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240 Global<Context>* realms_;
241 Global<Value> realm_shared_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000242
243 int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
244 int arg_offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000245 int RealmFind(Local<Context> context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000246};
247
248
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100249#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000250CounterMap* Shell::counter_map_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000251base::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000252CounterCollection Shell::local_counters_;
253CounterCollection* Shell::counters_ = &local_counters_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254base::LazyMutex Shell::context_mutex_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000255const base::TimeTicks Shell::kInitialTicks =
256 base::TimeTicks::HighResolutionNow();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000257Global<Context> Shell::utility_context_;
258base::LazyMutex Shell::workers_mutex_;
259bool Shell::allow_new_workers_ = true;
260i::List<Worker*> Shell::workers_;
261i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000262#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000263
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264Global<Context> Shell::evaluation_context_;
265ArrayBuffer::Allocator* Shell::array_buffer_allocator;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000266ShellOptions Shell::options;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000267base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
Steve Blocka7e24c12009-10-30 11:49:00 +0000268
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000269#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000270bool CounterMap::Match(void* key1, void* key2) {
271 const char* name1 = reinterpret_cast<const char*>(key1);
272 const char* name2 = reinterpret_cast<const char*>(key2);
273 return strcmp(name1, name2) == 0;
274}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000275#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000276
277
278// Converts a V8 value to a C string.
Steve Block6ded16b2010-05-10 14:33:55 +0100279const char* Shell::ToCString(const v8::String::Utf8Value& value) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000280 return *value ? *value : "<string conversion failed>";
281}
282
283
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400284ScriptCompiler::CachedData* CompileForCachedData(
285 Local<String> source, Local<Value> name,
286 ScriptCompiler::CompileOptions compile_options) {
287 int source_length = source->Length();
288 uint16_t* source_buffer = new uint16_t[source_length];
289 source->Write(source_buffer, 0, source_length);
290 int name_length = 0;
291 uint16_t* name_buffer = NULL;
292 if (name->IsString()) {
293 Local<String> name_string = Local<String>::Cast(name);
294 name_length = name_string->Length();
295 name_buffer = new uint16_t[name_length];
296 name_string->Write(name_buffer, 0, name_length);
297 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 Isolate::CreateParams create_params;
299 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
300 Isolate* temp_isolate = Isolate::New(create_params);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400301 ScriptCompiler::CachedData* result = NULL;
302 {
303 Isolate::Scope isolate_scope(temp_isolate);
304 HandleScope handle_scope(temp_isolate);
305 Context::Scope context_scope(Context::New(temp_isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000306 Local<String> source_copy =
307 v8::String::NewFromTwoByte(temp_isolate, source_buffer,
308 v8::NewStringType::kNormal,
309 source_length).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400310 Local<Value> name_copy;
311 if (name_buffer) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000312 name_copy = v8::String::NewFromTwoByte(temp_isolate, name_buffer,
313 v8::NewStringType::kNormal,
314 name_length).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400315 } else {
316 name_copy = v8::Undefined(temp_isolate);
317 }
318 ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000319 if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source,
320 compile_options).IsEmpty() &&
321 script_source.GetCachedData()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400322 int length = script_source.GetCachedData()->length;
323 uint8_t* cache = new uint8_t[length];
324 memcpy(cache, script_source.GetCachedData()->data, length);
325 result = new ScriptCompiler::CachedData(
326 cache, length, ScriptCompiler::CachedData::BufferOwned);
327 }
328 }
329 temp_isolate->Dispose();
330 delete[] source_buffer;
331 delete[] name_buffer;
332 return result;
333}
334
335
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000336// Compile a string within the current v8 context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337MaybeLocal<Script> Shell::CompileString(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000338 Isolate* isolate, Local<String> source, Local<Value> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000339 ScriptCompiler::CompileOptions compile_options, SourceType source_type) {
340 Local<Context> context(isolate->GetCurrentContext());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000341 ScriptOrigin origin(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400342 if (compile_options == ScriptCompiler::kNoCompileOptions) {
343 ScriptCompiler::Source script_source(source, origin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 return source_type == SCRIPT
345 ? ScriptCompiler::Compile(context, &script_source,
346 compile_options)
347 : ScriptCompiler::CompileModule(context, &script_source,
348 compile_options);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000349 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400350
351 ScriptCompiler::CachedData* data =
352 CompileForCachedData(source, name, compile_options);
353 ScriptCompiler::Source cached_source(source, origin, data);
354 if (compile_options == ScriptCompiler::kProduceCodeCache) {
355 compile_options = ScriptCompiler::kConsumeCodeCache;
356 } else if (compile_options == ScriptCompiler::kProduceParserCache) {
357 compile_options = ScriptCompiler::kConsumeParserCache;
358 } else {
359 DCHECK(false); // A new compile option?
360 }
361 if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000362 MaybeLocal<Script> result =
363 source_type == SCRIPT
364 ? ScriptCompiler::Compile(context, &cached_source, compile_options)
365 : ScriptCompiler::CompileModule(context, &cached_source,
366 compile_options);
367 CHECK(data == NULL || !data->rejected);
368 return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000369}
370
371
Steve Blocka7e24c12009-10-30 11:49:00 +0000372// Executes a string within the current v8 context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000373bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
374 Local<Value> name, bool print_result,
375 bool report_exceptions, SourceType source_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376 HandleScope handle_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000377 TryCatch try_catch(isolate);
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 {
417 v8::TryCatch try_catch(isolate);
418 v8::Local<v8::Context> context =
419 v8::Local<v8::Context>::New(isolate, utility_context_);
420 v8::Context::Scope context_scope(context);
421 Local<Object> global = context->Global();
422 Local<Value> fun =
423 global->Get(context, String::NewFromUtf8(isolate, "Stringify",
424 v8::NewStringType::kNormal)
425 .ToLocalChecked()).ToLocalChecked();
426 Local<Value> argv[1] = {result};
427 Local<Value> s;
428 if (!Local<Function>::Cast(fun)
429 ->Call(context, global, 1, argv)
430 .ToLocal(&s)) {
431 return true;
432 }
433 DCHECK(!try_catch.HasCaught());
434 v8::String::Utf8Value str(s);
435 fwrite(*str, sizeof(**str), str.length(), stdout);
436 printf("\n");
437 }
438#endif
439 }
440 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000441}
442
443
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000444PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
445 data_->realm_count_ = 1;
446 data_->realm_current_ = 0;
447 data_->realm_switch_ = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000448 data_->realms_ = new Global<Context>[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000449 data_->realms_[0].Reset(data_->isolate_,
450 data_->isolate_->GetEnteredContext());
Steve Blocka7e24c12009-10-30 11:49:00 +0000451}
452
453
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000454PerIsolateData::RealmScope::~RealmScope() {
455 // Drop realms to avoid keeping them alive.
456 for (int i = 0; i < data_->realm_count_; ++i)
457 data_->realms_[i].Reset();
458 delete[] data_->realms_;
459 if (!data_->realm_shared_.IsEmpty())
460 data_->realm_shared_.Reset();
461}
462
463
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000464int PerIsolateData::RealmFind(Local<Context> context) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000465 for (int i = 0; i < realm_count_; ++i) {
466 if (realms_[i] == context) return i;
467 }
468 return -1;
469}
470
471
472int PerIsolateData::RealmIndexOrThrow(
473 const v8::FunctionCallbackInfo<v8::Value>& args,
474 int arg_offset) {
475 if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
476 Throw(args.GetIsolate(), "Invalid argument");
477 return -1;
478 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000479 int index = args[arg_offset]
480 ->Int32Value(args.GetIsolate()->GetCurrentContext())
481 .FromMaybe(-1);
482 if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000483 Throw(args.GetIsolate(), "Invalid realm index");
484 return -1;
485 }
486 return index;
487}
488
489
490#ifndef V8_SHARED
491// performance.now() returns a time stamp as double, measured in milliseconds.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000492// When FLAG_verify_predictable mode is enabled it returns result of
493// v8::Platform::MonotonicallyIncreasingTime().
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000494void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
495 if (i::FLAG_verify_predictable) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000496 args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000497 } else {
498 base::TimeDelta delta =
499 base::TimeTicks::HighResolutionNow() - kInitialTicks;
500 args.GetReturnValue().Set(delta.InMillisecondsF());
501 }
502}
503#endif // !V8_SHARED
504
505
506// Realm.current() returns the index of the currently active realm.
507void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
508 Isolate* isolate = args.GetIsolate();
509 PerIsolateData* data = PerIsolateData::Get(isolate);
510 int index = data->RealmFind(isolate->GetEnteredContext());
511 if (index == -1) return;
512 args.GetReturnValue().Set(index);
513}
514
515
516// Realm.owner(o) returns the index of the realm that created o.
517void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
518 Isolate* isolate = args.GetIsolate();
519 PerIsolateData* data = PerIsolateData::Get(isolate);
520 if (args.Length() < 1 || !args[0]->IsObject()) {
521 Throw(args.GetIsolate(), "Invalid argument");
522 return;
523 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000524 int index = data->RealmFind(args[0]
525 ->ToObject(isolate->GetCurrentContext())
526 .ToLocalChecked()
527 ->CreationContext());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000528 if (index == -1) return;
529 args.GetReturnValue().Set(index);
530}
531
532
533// Realm.global(i) returns the global object of realm i.
534// (Note that properties of global objects cannot be read/written cross-realm.)
535void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
536 PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
537 int index = data->RealmIndexOrThrow(args, 0);
538 if (index == -1) return;
539 args.GetReturnValue().Set(
540 Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
541}
542
543
544// Realm.create() creates a new realm and returns its index.
545void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
546 Isolate* isolate = args.GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000547 TryCatch try_catch(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 PerIsolateData* data = PerIsolateData::Get(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000549 Global<Context>* old_realms = data->realms_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 int index = data->realm_count_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000551 data->realms_ = new Global<Context>[++data->realm_count_];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000552 for (int i = 0; i < index; ++i) {
553 data->realms_[i].Reset(isolate, old_realms[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000554 old_realms[i].Reset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000555 }
556 delete[] old_realms;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000557 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
558 Local<Context> context = Context::New(isolate, NULL, global_template);
559 if (context.IsEmpty()) {
560 DCHECK(try_catch.HasCaught());
561 try_catch.ReThrow();
562 return;
563 }
564 data->realms_[index].Reset(isolate, context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000565 args.GetReturnValue().Set(index);
566}
567
568
569// Realm.dispose(i) disposes the reference to the realm i.
570void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
571 Isolate* isolate = args.GetIsolate();
572 PerIsolateData* data = PerIsolateData::Get(isolate);
573 int index = data->RealmIndexOrThrow(args, 0);
574 if (index == -1) return;
575 if (index == 0 ||
576 index == data->realm_current_ || index == data->realm_switch_) {
577 Throw(args.GetIsolate(), "Invalid realm index");
578 return;
579 }
580 data->realms_[index].Reset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000581 isolate->ContextDisposedNotification();
582 isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000583}
584
585
586// Realm.switch(i) switches to the realm i for consecutive interactive inputs.
587void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
588 Isolate* isolate = args.GetIsolate();
589 PerIsolateData* data = PerIsolateData::Get(isolate);
590 int index = data->RealmIndexOrThrow(args, 0);
591 if (index == -1) return;
592 data->realm_switch_ = index;
593}
594
595
596// Realm.eval(i, s) evaluates s in realm i and returns the result.
597void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
598 Isolate* isolate = args.GetIsolate();
599 PerIsolateData* data = PerIsolateData::Get(isolate);
600 int index = data->RealmIndexOrThrow(args, 0);
601 if (index == -1) return;
602 if (args.Length() < 2 || !args[1]->IsString()) {
603 Throw(args.GetIsolate(), "Invalid argument");
604 return;
605 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000606 ScriptCompiler::Source script_source(
607 args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
608 Local<UnboundScript> script;
609 if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
610 .ToLocal(&script)) {
611 return;
612 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000613 Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
614 realm->Enter();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000615 Local<Value> result;
616 if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
617 realm->Exit();
618 return;
619 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000620 realm->Exit();
621 args.GetReturnValue().Set(result);
622}
623
624
625// Realm.shared is an accessor for a single shared value across realms.
626void Shell::RealmSharedGet(Local<String> property,
627 const PropertyCallbackInfo<Value>& info) {
628 Isolate* isolate = info.GetIsolate();
629 PerIsolateData* data = PerIsolateData::Get(isolate);
630 if (data->realm_shared_.IsEmpty()) return;
631 info.GetReturnValue().Set(data->realm_shared_);
632}
633
634void Shell::RealmSharedSet(Local<String> property,
635 Local<Value> value,
636 const PropertyCallbackInfo<void>& info) {
637 Isolate* isolate = info.GetIsolate();
638 PerIsolateData* data = PerIsolateData::Get(isolate);
639 data->realm_shared_.Reset(isolate, value);
640}
641
642
643void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
644 Write(args);
645 printf("\n");
646 fflush(stdout);
647}
648
649
650void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000651 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000652 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000653 if (i != 0) {
654 printf(" ");
655 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000656
657 // Explicitly catch potential exceptions in toString().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000658 v8::TryCatch try_catch(args.GetIsolate());
659 Local<Value> arg = args[i];
660 Local<String> str_obj;
661
662 if (arg->IsSymbol()) {
663 arg = Local<Symbol>::Cast(arg)->Name();
664 }
665 if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
666 .ToLocal(&str_obj)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000667 try_catch.ReThrow();
668 return;
669 }
670
671 v8::String::Utf8Value str(str_obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000672 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
Steve Blockd0582a62009-12-15 09:54:21 +0000673 if (n != str.length()) {
674 printf("Error in fwrite\n");
Ben Murdoch589d6972011-11-30 16:04:58 +0000675 Exit(1);
Steve Blockd0582a62009-12-15 09:54:21 +0000676 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000677 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000678}
679
680
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000681void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000682 String::Utf8Value file(args[0]);
683 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000684 Throw(args.GetIsolate(), "Error loading file");
685 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000687 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000688 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000689 Throw(args.GetIsolate(), "Error loading file");
690 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000691 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000692 args.GetReturnValue().Set(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000693}
694
695
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000696Local<String> Shell::ReadFromStdin(Isolate* isolate) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000697 static const int kBufferSize = 256;
698 char buffer[kBufferSize];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000699 Local<String> accumulator =
700 String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000701 int length;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000702 while (true) {
703 // Continue reading if the line ends with an escape '\\' or the line has
704 // not been fully read into the buffer yet (does not end with '\n').
705 // If fgets gets an error, just give up.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100706 char* input = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000707 input = fgets(buffer, kBufferSize, stdin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000708 if (input == NULL) return Local<String>();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000709 length = static_cast<int>(strlen(buffer));
710 if (length == 0) {
711 return accumulator;
712 } else if (buffer[length-1] != '\n') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000713 accumulator = String::Concat(
714 accumulator,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000715 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
716 .ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000717 } else if (length > 1 && buffer[length-2] == '\\') {
718 buffer[length-2] = '\n';
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000719 accumulator = String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000720 accumulator,
721 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
722 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000723 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000724 return String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000725 accumulator,
726 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
727 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000728 }
729 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000730}
731
732
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000733void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000735 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000736 String::Utf8Value file(args[i]);
737 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000738 Throw(args.GetIsolate(), "Error loading file");
739 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000740 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000741 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000742 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000743 Throw(args.GetIsolate(), "Error loading file");
744 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000745 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000746 if (!ExecuteString(
747 args.GetIsolate(), source,
748 String::NewFromUtf8(args.GetIsolate(), *file,
749 NewStringType::kNormal).ToLocalChecked(),
750 false, true)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000751 Throw(args.GetIsolate(), "Error executing file");
752 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000753 }
754 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100755}
756
757
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000758#ifndef V8_SHARED
759void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
760 Isolate* isolate = args.GetIsolate();
761 HandleScope handle_scope(isolate);
762 if (args.Length() < 1 || !args[0]->IsString()) {
763 Throw(args.GetIsolate(), "1st argument must be string");
764 return;
765 }
766
767 if (!args.IsConstructCall()) {
768 Throw(args.GetIsolate(), "Worker must be constructed with new");
769 return;
770 }
771
772 {
773 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
774 if (workers_.length() >= kMaxWorkers) {
775 Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
776 return;
777 }
778
779 // Initialize the internal field to NULL; if we return early without
780 // creating a new Worker (because the main thread is terminating) we can
781 // early-out from the instance calls.
782 args.Holder()->SetAlignedPointerInInternalField(0, NULL);
783
784 if (!allow_new_workers_) return;
785
786 Worker* worker = new Worker;
787 args.Holder()->SetAlignedPointerInInternalField(0, worker);
788 workers_.Add(worker);
789
790 String::Utf8Value script(args[0]);
791 if (!*script) {
792 Throw(args.GetIsolate(), "Can't get worker script");
793 return;
794 }
795 worker->StartExecuteInThread(*script);
796 }
797}
798
799
800void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
801 Isolate* isolate = args.GetIsolate();
802 HandleScope handle_scope(isolate);
803 Local<Context> context = isolate->GetCurrentContext();
804
805 if (args.Length() < 1) {
806 Throw(isolate, "Invalid argument");
807 return;
808 }
809
810 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
811 if (!worker) {
812 return;
813 }
814
815 Local<Value> message = args[0];
816 ObjectList to_transfer;
817 if (args.Length() >= 2) {
818 if (!args[1]->IsArray()) {
819 Throw(isolate, "Transfer list must be an Array");
820 return;
821 }
822
823 Local<Array> transfer = Local<Array>::Cast(args[1]);
824 uint32_t length = transfer->Length();
825 for (uint32_t i = 0; i < length; ++i) {
826 Local<Value> element;
827 if (transfer->Get(context, i).ToLocal(&element)) {
828 if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) {
829 Throw(isolate,
830 "Transfer array elements must be an ArrayBuffer or "
831 "SharedArrayBuffer.");
832 break;
833 }
834
835 to_transfer.Add(Local<Object>::Cast(element));
836 }
837 }
838 }
839
840 ObjectList seen_objects;
841 SerializationData* data = new SerializationData;
842 if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) {
843 worker->PostMessage(data);
844 } else {
845 delete data;
846 }
847}
848
849
850void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
851 Isolate* isolate = args.GetIsolate();
852 HandleScope handle_scope(isolate);
853 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
854 if (!worker) {
855 return;
856 }
857
858 SerializationData* data = worker->GetMessage();
859 if (data) {
860 int offset = 0;
861 Local<Value> data_value;
862 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
863 args.GetReturnValue().Set(data_value);
864 }
865 delete data;
866 }
867}
868
869
870void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
871 Isolate* isolate = args.GetIsolate();
872 HandleScope handle_scope(isolate);
873 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
874 if (!worker) {
875 return;
876 }
877
878 worker->Terminate();
879}
880#endif // !V8_SHARED
881
882
883void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
884 int exit_code = (*args)[0]
885 ->Int32Value(args->GetIsolate()->GetCurrentContext())
886 .FromMaybe(0);
887#ifndef V8_SHARED
888 CleanupWorkers();
889#endif // !V8_SHARED
890 OnExit(args->GetIsolate());
891 Exit(exit_code);
892}
893
894
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000895void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000896 base::CallOnce(&quit_once_, &QuitOnce,
897 const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
Steve Blocka7e24c12009-10-30 11:49:00 +0000898}
899
900
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000901void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
902 args.GetReturnValue().Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000903 String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
904 NewStringType::kNormal).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000905}
906
907
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
909 HandleScope handle_scope(isolate);
910#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000911 Local<Context> utility_context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000912 bool enter_context = !isolate->InContext();
913 if (enter_context) {
914 utility_context = Local<Context>::New(isolate, utility_context_);
915 utility_context->Enter();
916 }
917#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000918 v8::String::Utf8Value exception(try_catch->Exception());
919 const char* exception_string = ToCString(exception);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000920 Local<Message> message = try_catch->Message();
Steve Blocka7e24c12009-10-30 11:49:00 +0000921 if (message.IsEmpty()) {
922 // V8 didn't provide any extra information about this error; just
923 // print the exception.
924 printf("%s\n", exception_string);
925 } else {
926 // Print (filename):(line number): (message).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000927 v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
Steve Blocka7e24c12009-10-30 11:49:00 +0000928 const char* filename_string = ToCString(filename);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000929 int linenum =
930 message->GetLineNumber(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000931 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
932 // Print line of source code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000933 v8::String::Utf8Value sourceline(
934 message->GetSourceLine(isolate->GetCurrentContext()).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000935 const char* sourceline_string = ToCString(sourceline);
936 printf("%s\n", sourceline_string);
937 // Print wavy underline (GetUnderline is deprecated).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000938 int start =
939 message->GetStartColumn(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000940 for (int i = 0; i < start; i++) {
941 printf(" ");
942 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000943 int end = message->GetEndColumn(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000944 for (int i = start; i < end; i++) {
945 printf("^");
946 }
947 printf("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000948 Local<Value> stack_trace_string;
949 if (try_catch->StackTrace(isolate->GetCurrentContext())
950 .ToLocal(&stack_trace_string) &&
951 stack_trace_string->IsString()) {
952 v8::String::Utf8Value stack_trace(
953 Local<String>::Cast(stack_trace_string));
954 printf("%s\n", ToCString(stack_trace));
Ben Murdoch257744e2011-11-30 15:57:28 +0000955 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000956 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000957 printf("\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000958#ifndef V8_SHARED
959 if (enter_context) utility_context->Exit();
960#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000961}
962
963
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000964#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000965int32_t* Counter::Bind(const char* name, bool is_histogram) {
966 int i;
967 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
968 name_[i] = static_cast<char>(name[i]);
969 name_[i] = '\0';
970 is_histogram_ = is_histogram;
971 return ptr();
972}
973
974
975void Counter::AddSample(int32_t sample) {
976 count_++;
977 sample_total_ += sample;
978}
979
980
981CounterCollection::CounterCollection() {
982 magic_number_ = 0xDEADFACE;
983 max_counters_ = kMaxCounters;
984 max_name_size_ = Counter::kMaxNameSize;
985 counters_in_use_ = 0;
986}
987
988
989Counter* CounterCollection::GetNextCounter() {
990 if (counters_in_use_ == kMaxCounters) return NULL;
991 return &counters_[counters_in_use_++];
992}
993
994
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000995void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
996 counters_file_ = base::OS::MemoryMappedFile::create(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000997 name, sizeof(CounterCollection), &local_counters_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000998 void* memory = (counters_file_ == NULL) ?
999 NULL : counters_file_->memory();
1000 if (memory == NULL) {
1001 printf("Could not map counters file %s\n", name);
Ben Murdoch589d6972011-11-30 16:04:58 +00001002 Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001003 }
1004 counters_ = static_cast<CounterCollection*>(memory);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001005 isolate->SetCounterFunction(LookupCounter);
1006 isolate->SetCreateHistogramFunction(CreateHistogram);
1007 isolate->SetAddHistogramSampleFunction(AddHistogramSample);
Steve Blocka7e24c12009-10-30 11:49:00 +00001008}
1009
1010
1011int CounterMap::Hash(const char* name) {
1012 int h = 0;
1013 int c;
1014 while ((c = *name++) != 0) {
1015 h += h << 5;
1016 h += c;
1017 }
1018 return h;
1019}
1020
1021
1022Counter* Shell::GetCounter(const char* name, bool is_histogram) {
1023 Counter* counter = counter_map_->Lookup(name);
1024
1025 if (counter == NULL) {
1026 counter = counters_->GetNextCounter();
1027 if (counter != NULL) {
1028 counter_map_->Set(name, counter);
1029 counter->Bind(name, is_histogram);
1030 }
1031 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001032 DCHECK(counter->is_histogram() == is_histogram);
Steve Blocka7e24c12009-10-30 11:49:00 +00001033 }
1034 return counter;
1035}
1036
1037
1038int* Shell::LookupCounter(const char* name) {
1039 Counter* counter = GetCounter(name, false);
1040
1041 if (counter != NULL) {
1042 return counter->ptr();
1043 } else {
1044 return NULL;
1045 }
1046}
1047
1048
1049void* Shell::CreateHistogram(const char* name,
1050 int min,
1051 int max,
1052 size_t buckets) {
1053 return GetCounter(name, true);
1054}
1055
1056
1057void Shell::AddHistogramSample(void* histogram, int sample) {
1058 Counter* counter = reinterpret_cast<Counter*>(histogram);
1059 counter->AddSample(sample);
1060}
1061
1062
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001063class NoUseStrongForUtilityScriptScope {
1064 public:
1065 NoUseStrongForUtilityScriptScope() : flag_(i::FLAG_use_strong) {
1066 i::FLAG_use_strong = false;
1067 }
1068 ~NoUseStrongForUtilityScriptScope() { i::FLAG_use_strong = flag_; }
1069
1070 private:
1071 bool flag_;
1072};
1073
1074
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001075void Shell::InstallUtilityScript(Isolate* isolate) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001076 NoUseStrongForUtilityScriptScope no_use_strong;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001077 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001078 // If we use the utility context, we have to set the security tokens so that
1079 // utility, evaluation and debug context can all access each other.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001080 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
1081 utility_context_.Reset(isolate, Context::New(isolate, NULL, global_template));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001082 v8::Local<v8::Context> utility_context =
1083 v8::Local<v8::Context>::New(isolate, utility_context_);
1084 v8::Local<v8::Context> evaluation_context =
1085 v8::Local<v8::Context>::New(isolate, evaluation_context_);
1086 utility_context->SetSecurityToken(Undefined(isolate));
1087 evaluation_context->SetSecurityToken(Undefined(isolate));
1088 v8::Context::Scope context_scope(utility_context);
Steve Blocka7e24c12009-10-30 11:49:00 +00001089
Steve Blocka7e24c12009-10-30 11:49:00 +00001090 // Run the d8 shell utility script in the utility context
1091 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001092 i::Vector<const char> shell_source =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001093 i::NativesCollection<i::D8>::GetScriptSource(source_index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001094 i::Vector<const char> shell_source_name =
1095 i::NativesCollection<i::D8>::GetScriptName(source_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001096 Local<String> source =
1097 String::NewFromUtf8(isolate, shell_source.start(), NewStringType::kNormal,
1098 shell_source.length()).ToLocalChecked();
1099 Local<String> name =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001100 String::NewFromUtf8(isolate, shell_source_name.start(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001101 NewStringType::kNormal,
1102 shell_source_name.length()).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001103 ScriptOrigin origin(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001104 Local<Script> script =
1105 Script::Compile(utility_context, source, &origin).ToLocalChecked();
1106 script->Run(utility_context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001107 // Mark the d8 shell script as native to avoid it showing up as normal source
1108 // in the debugger.
Steve Block6ded16b2010-05-10 14:33:55 +01001109 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
1110 i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
1111 ? i::Handle<i::Script>(i::Script::cast(
1112 i::JSFunction::cast(*compiled_script)->shared()->script()))
1113 : i::Handle<i::Script>(i::Script::cast(
1114 i::SharedFunctionInfo::cast(*compiled_script)->script()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001115 script_object->set_type(i::Script::TYPE_EXTENSION);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001116}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001117#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001118
1119
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001120Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
1121 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
1122 global_template->Set(
1123 String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
1124 .ToLocalChecked(),
1125 FunctionTemplate::New(isolate, Print));
1126 global_template->Set(
1127 String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
1128 .ToLocalChecked(),
1129 FunctionTemplate::New(isolate, Write));
1130 global_template->Set(
1131 String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
1132 .ToLocalChecked(),
1133 FunctionTemplate::New(isolate, Read));
1134 global_template->Set(
1135 String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
1136 .ToLocalChecked(),
1137 FunctionTemplate::New(isolate, ReadBuffer));
1138 global_template->Set(
1139 String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
1140 .ToLocalChecked(),
1141 FunctionTemplate::New(isolate, ReadLine));
1142 global_template->Set(
1143 String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
1144 .ToLocalChecked(),
1145 FunctionTemplate::New(isolate, Load));
1146 // Some Emscripten-generated code tries to call 'quit', which in turn would
1147 // call C's exit(). This would lead to memory leaks, because there is no way
1148 // we can terminate cleanly then, so we need a way to hide 'quit'.
1149 if (!options.omit_quit) {
1150 global_template->Set(
1151 String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
1152 .ToLocalChecked(),
1153 FunctionTemplate::New(isolate, Quit));
1154 }
1155 global_template->Set(
1156 String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
1157 .ToLocalChecked(),
1158 FunctionTemplate::New(isolate, Version));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001159
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001160 // Bind the Realm object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001161 Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
1162 realm_template->Set(
1163 String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
1164 .ToLocalChecked(),
1165 FunctionTemplate::New(isolate, RealmCurrent));
1166 realm_template->Set(
1167 String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
1168 .ToLocalChecked(),
1169 FunctionTemplate::New(isolate, RealmOwner));
1170 realm_template->Set(
1171 String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1172 .ToLocalChecked(),
1173 FunctionTemplate::New(isolate, RealmGlobal));
1174 realm_template->Set(
1175 String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
1176 .ToLocalChecked(),
1177 FunctionTemplate::New(isolate, RealmCreate));
1178 realm_template->Set(
1179 String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
1180 .ToLocalChecked(),
1181 FunctionTemplate::New(isolate, RealmDispose));
1182 realm_template->Set(
1183 String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
1184 .ToLocalChecked(),
1185 FunctionTemplate::New(isolate, RealmSwitch));
1186 realm_template->Set(
1187 String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
1188 .ToLocalChecked(),
1189 FunctionTemplate::New(isolate, RealmEval));
1190 realm_template->SetAccessor(
1191 String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
1192 .ToLocalChecked(),
1193 RealmSharedGet, RealmSharedSet);
1194 global_template->Set(
1195 String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
1196 .ToLocalChecked(),
1197 realm_template);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001198
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001199#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001200 Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
1201 performance_template->Set(
1202 String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
1203 .ToLocalChecked(),
1204 FunctionTemplate::New(isolate, PerformanceNow));
1205 global_template->Set(
1206 String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
1207 .ToLocalChecked(),
1208 performance_template);
1209
1210 Local<FunctionTemplate> worker_fun_template =
1211 FunctionTemplate::New(isolate, WorkerNew);
1212 Local<Signature> worker_signature =
1213 Signature::New(isolate, worker_fun_template);
1214 worker_fun_template->SetClassName(
1215 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1216 .ToLocalChecked());
1217 worker_fun_template->ReadOnlyPrototype();
1218 worker_fun_template->PrototypeTemplate()->Set(
1219 String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
1220 .ToLocalChecked(),
1221 FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
1222 worker_signature));
1223 worker_fun_template->PrototypeTemplate()->Set(
1224 String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
1225 .ToLocalChecked(),
1226 FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
1227 worker_signature));
1228 worker_fun_template->PrototypeTemplate()->Set(
1229 String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
1230 .ToLocalChecked(),
1231 FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
1232 worker_signature));
1233 worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
1234 global_template->Set(
1235 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1236 .ToLocalChecked(),
1237 worker_fun_template);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001238#endif // !V8_SHARED
1239
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240 Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001241 AddOSMethods(isolate, os_templ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001242 global_template->Set(
1243 String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
1244 .ToLocalChecked(),
1245 os_templ);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001246
1247 return global_template;
Steve Blocka7e24c12009-10-30 11:49:00 +00001248}
1249
1250
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001251void Shell::Initialize(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001252#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001253 // Set up counters
1254 if (i::StrLength(i::FLAG_map_counters) != 0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001255 MapCounters(isolate, i::FLAG_map_counters);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001256#endif // !V8_SHARED
1257}
1258
1259
1260Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001261#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001262 // This needs to be a critical section since this is not thread-safe
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001263 base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001264#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001265 // Initialize the global objects
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001266 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001267 EscapableHandleScope handle_scope(isolate);
1268 Local<Context> context = Context::New(isolate, NULL, global_template);
1269 DCHECK(!context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001270 Context::Scope scope(context);
1271
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001272#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001273 i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001274 i::JSArguments js_args = i::FLAG_js_arguments;
1275 i::Handle<i::FixedArray> arguments_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001276 factory->NewFixedArray(js_args.argc);
1277 for (int j = 0; j < js_args.argc; j++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001278 i::Handle<i::String> arg =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001279 factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001280 arguments_array->set(j, *arg);
1281 }
1282 i::Handle<i::JSArray> arguments_jsarray =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001283 factory->NewJSArrayWithElements(arguments_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001284 context->Global()
1285 ->Set(context,
1286 String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
1287 .ToLocalChecked(),
1288 Utils::ToLocal(arguments_jsarray))
1289 .FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001290#endif // !V8_SHARED
1291 return handle_scope.Escape(context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001292}
1293
1294
Ben Murdoch589d6972011-11-30 16:04:58 +00001295void Shell::Exit(int exit_code) {
1296 // Use _exit instead of exit to avoid races between isolate
1297 // threads and static destructors.
1298 fflush(stdout);
1299 fflush(stderr);
1300 _exit(exit_code);
1301}
1302
1303
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001304#ifndef V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001305struct CounterAndKey {
1306 Counter* counter;
1307 const char* key;
1308};
1309
1310
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001311inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
1312 return strcmp(lhs.key, rhs.key) < 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001313}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001314#endif // !V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001315
1316
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001317void Shell::OnExit(v8::Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001318#ifndef V8_SHARED
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001319 reinterpret_cast<i::Isolate*>(isolate)->DumpAndResetCompilationStats();
Steve Blocka7e24c12009-10-30 11:49:00 +00001320 if (i::FLAG_dump_counters) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001321 int number_of_counters = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001322 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001323 number_of_counters++;
1324 }
1325 CounterAndKey* counters = new CounterAndKey[number_of_counters];
1326 int j = 0;
1327 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
1328 counters[j].counter = i.CurrentValue();
1329 counters[j].key = i.CurrentKey();
1330 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001331 std::sort(counters, counters + number_of_counters);
1332 printf("+----------------------------------------------------------------+"
1333 "-------------+\n");
1334 printf("| Name |"
1335 " Value |\n");
1336 printf("+----------------------------------------------------------------+"
1337 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001338 for (j = 0; j < number_of_counters; j++) {
1339 Counter* counter = counters[j].counter;
1340 const char* key = counters[j].key;
Steve Blocka7e24c12009-10-30 11:49:00 +00001341 if (counter->is_histogram()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001342 printf("| c:%-60s | %11i |\n", key, counter->count());
1343 printf("| t:%-60s | %11i |\n", key, counter->sample_total());
Steve Blocka7e24c12009-10-30 11:49:00 +00001344 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001345 printf("| %-62s | %11i |\n", key, counter->count());
Steve Blocka7e24c12009-10-30 11:49:00 +00001346 }
1347 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001348 printf("+----------------------------------------------------------------+"
1349 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001350 delete [] counters;
Steve Blocka7e24c12009-10-30 11:49:00 +00001351 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001352 delete counters_file_;
1353 delete counter_map_;
1354#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001355}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001356
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001357
1358
1359static FILE* FOpen(const char* path, const char* mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001360#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001361 FILE* result;
1362 if (fopen_s(&result, path, mode) == 0) {
1363 return result;
1364 } else {
1365 return NULL;
1366 }
1367#else
1368 FILE* file = fopen(path, mode);
1369 if (file == NULL) return NULL;
1370 struct stat file_stat;
1371 if (fstat(fileno(file), &file_stat) != 0) return NULL;
1372 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
1373 if (is_regular_file) return file;
1374 fclose(file);
1375 return NULL;
1376#endif
1377}
Steve Blocka7e24c12009-10-30 11:49:00 +00001378
1379
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001380static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001381 FILE* file = FOpen(name, "rb");
Steve Blocka7e24c12009-10-30 11:49:00 +00001382 if (file == NULL) return NULL;
1383
1384 fseek(file, 0, SEEK_END);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001385 size_t size = ftell(file);
Steve Blocka7e24c12009-10-30 11:49:00 +00001386 rewind(file);
1387
1388 char* chars = new char[size + 1];
1389 chars[size] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001390 for (size_t i = 0; i < size;) {
1391 i += fread(&chars[i], 1, size - i, file);
1392 if (ferror(file)) {
1393 fclose(file);
1394 delete[] chars;
1395 return nullptr;
1396 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001397 }
1398 fclose(file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001399 *size_out = static_cast<int>(size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001400 return chars;
1401}
1402
1403
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001404struct DataAndPersistent {
1405 uint8_t* data;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001406 int byte_length;
1407 Global<ArrayBuffer> handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001408};
1409
1410
1411static void ReadBufferWeakCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001412 const v8::WeakCallbackInfo<DataAndPersistent>& data) {
1413 int byte_length = data.GetParameter()->byte_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001414 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
1415 -static_cast<intptr_t>(byte_length));
1416
1417 delete[] data.GetParameter()->data;
1418 data.GetParameter()->handle.Reset();
1419 delete data.GetParameter();
1420}
1421
1422
1423void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
1424 DCHECK(sizeof(char) == sizeof(uint8_t)); // NOLINT
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001425 String::Utf8Value filename(args[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001426 int length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001427 if (*filename == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001428 Throw(args.GetIsolate(), "Error loading file");
1429 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001430 }
1431
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001432 Isolate* isolate = args.GetIsolate();
1433 DataAndPersistent* data = new DataAndPersistent;
1434 data->data = reinterpret_cast<uint8_t*>(
1435 ReadChars(args.GetIsolate(), *filename, &length));
1436 if (data->data == NULL) {
1437 delete data;
1438 Throw(args.GetIsolate(), "Error reading file");
1439 return;
1440 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001441 data->byte_length = length;
1442 Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001443 data->handle.Reset(isolate, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001444 data->handle.SetWeak(data, ReadBufferWeakCallback,
1445 v8::WeakCallbackType::kParameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001446 data->handle.MarkIndependent();
1447 isolate->AdjustAmountOfExternalAllocatedMemory(length);
1448
1449 args.GetReturnValue().Set(buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00001450}
1451
1452
Steve Blocka7e24c12009-10-30 11:49:00 +00001453// Reads a file into a v8 string.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001454Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001455 int size = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001456 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001457 if (chars == NULL) return Local<String>();
1458 Local<String> result =
1459 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1460 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001461 delete[] chars;
1462 return result;
1463}
1464
1465
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001466void Shell::RunShell(Isolate* isolate) {
1467 HandleScope outer_scope(isolate);
1468 v8::Local<v8::Context> context =
1469 v8::Local<v8::Context>::New(isolate, evaluation_context_);
1470 v8::Context::Scope context_scope(context);
1471 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001472 Local<String> name =
1473 String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
1474 .ToLocalChecked();
1475 printf("V8 version %s\n", V8::GetVersion());
Steve Blocka7e24c12009-10-30 11:49:00 +00001476 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001477 HandleScope inner_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001478 printf("d8> ");
1479#if defined(__native_client__)
1480 // Native Client libc is used to being embedded in Chrome and
1481 // has trouble recognizing when to flush.
1482 fflush(stdout);
1483#endif
1484 Local<String> input = Shell::ReadFromStdin(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001485 if (input.IsEmpty()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001486 ExecuteString(isolate, input, name, true, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001487 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001488 printf("\n");
1489}
1490
1491
Ben Murdoch589d6972011-11-30 16:04:58 +00001492SourceGroup::~SourceGroup() {
1493#ifndef V8_SHARED
Ben Murdoch589d6972011-11-30 16:04:58 +00001494 delete thread_;
1495 thread_ = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001496#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001497}
Steve Blocka7e24c12009-10-30 11:49:00 +00001498
Steve Blocka7e24c12009-10-30 11:49:00 +00001499
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001500void SourceGroup::Execute(Isolate* isolate) {
1501 bool exception_was_thrown = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001502 for (int i = begin_offset_; i < end_offset_; ++i) {
1503 const char* arg = argv_[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001504 Shell::SourceType source_type = Shell::SCRIPT;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001505 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1506 // Execute argument given to -e option directly.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001507 HandleScope handle_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 Local<String> file_name =
1509 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1510 .ToLocalChecked();
1511 Local<String> source =
1512 String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
1513 .ToLocalChecked();
1514 Shell::options.script_executed = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001515 if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1516 exception_was_thrown = true;
1517 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001518 }
1519 ++i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001520 continue;
1521 } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
1522 // Treat the next file as a module.
1523 source_type = Shell::MODULE;
1524 arg = argv_[++i];
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001525 } else if (arg[0] == '-') {
1526 // Ignore other options. They have been parsed already.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001527 continue;
1528 }
1529
1530 // Use all other arguments as names of files to load and run.
1531 HandleScope handle_scope(isolate);
1532 Local<String> file_name =
1533 String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
1534 .ToLocalChecked();
1535 Local<String> source = ReadFile(isolate, arg);
1536 if (source.IsEmpty()) {
1537 printf("Error reading '%s'\n", arg);
1538 Shell::Exit(1);
1539 }
1540 Shell::options.script_executed = true;
1541 if (!Shell::ExecuteString(isolate, source, file_name, false, true,
1542 source_type)) {
1543 exception_was_thrown = true;
1544 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001545 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001546 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001547 if (exception_was_thrown != Shell::options.expected_to_throw) {
1548 Shell::Exit(1);
1549 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001550}
Steve Blocka7e24c12009-10-30 11:49:00 +00001551
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001552
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001553Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001554 int size;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001555 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001556 if (chars == NULL) return Local<String>();
1557 Local<String> result =
1558 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1559 .ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001560 delete[] chars;
1561 return result;
1562}
1563
1564
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001565#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001566base::Thread::Options SourceGroup::GetThreadOptions() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001567 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1568 // which is not enough to parse the big literal expressions used in tests.
1569 // The stack size should be at least StackGuard::kLimitSize + some
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001570 // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001571 return base::Thread::Options("IsolateThread", 2 * MB);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001572}
1573
1574
1575void SourceGroup::ExecuteInThread() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001576 Isolate::CreateParams create_params;
1577 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1578 Isolate* isolate = Isolate::New(create_params);
1579 for (int i = 0; i < Shell::options.stress_runs; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001580 next_semaphore_.Wait();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001581 {
1582 Isolate::Scope iscope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001583 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 HandleScope scope(isolate);
1585 PerIsolateData data(isolate);
1586 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1587 {
1588 Context::Scope cscope(context);
1589 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1590 Execute(isolate);
1591 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001592 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001593 Shell::CollectGarbage(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001594 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001595 done_semaphore_.Signal();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001596 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001597
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001598 isolate->Dispose();
1599}
1600
1601
1602void SourceGroup::StartExecuteInThread() {
1603 if (thread_ == NULL) {
1604 thread_ = new IsolateThread(this);
1605 thread_->Start();
1606 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001607 next_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001608}
1609
1610
1611void SourceGroup::WaitForThread() {
1612 if (thread_ == NULL) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001613 done_semaphore_.Wait();
1614}
1615
1616
1617void SourceGroup::JoinThread() {
1618 if (thread_ == NULL) return;
1619 thread_->Join();
1620}
1621
1622
1623SerializationData::~SerializationData() {
1624 // Any ArrayBuffer::Contents are owned by this SerializationData object if
1625 // ownership hasn't been transferred out via ReadArrayBufferContents.
1626 // SharedArrayBuffer::Contents may be used by multiple threads, so must be
1627 // cleaned up by the main thread in Shell::CleanupWorkers().
1628 for (int i = 0; i < array_buffer_contents_.length(); ++i) {
1629 ArrayBuffer::Contents& contents = array_buffer_contents_[i];
1630 if (contents.Data()) {
1631 Shell::array_buffer_allocator->Free(contents.Data(),
1632 contents.ByteLength());
1633 }
1634 }
1635}
1636
1637
1638void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); }
1639
1640
1641void SerializationData::WriteMemory(const void* p, int length) {
1642 if (length > 0) {
1643 i::Vector<uint8_t> block = data_.AddBlock(0, length);
1644 memcpy(&block[0], p, length);
1645 }
1646}
1647
1648
1649void SerializationData::WriteArrayBufferContents(
1650 const ArrayBuffer::Contents& contents) {
1651 array_buffer_contents_.Add(contents);
1652 WriteTag(kSerializationTagTransferredArrayBuffer);
1653 int index = array_buffer_contents_.length() - 1;
1654 Write(index);
1655}
1656
1657
1658void SerializationData::WriteSharedArrayBufferContents(
1659 const SharedArrayBuffer::Contents& contents) {
1660 shared_array_buffer_contents_.Add(contents);
1661 WriteTag(kSerializationTagTransferredSharedArrayBuffer);
1662 int index = shared_array_buffer_contents_.length() - 1;
1663 Write(index);
1664}
1665
1666
1667SerializationTag SerializationData::ReadTag(int* offset) const {
1668 return static_cast<SerializationTag>(Read<uint8_t>(offset));
1669}
1670
1671
1672void SerializationData::ReadMemory(void* p, int length, int* offset) const {
1673 if (length > 0) {
1674 memcpy(p, &data_[*offset], length);
1675 (*offset) += length;
1676 }
1677}
1678
1679
1680void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents,
1681 int* offset) const {
1682 int index = Read<int>(offset);
1683 DCHECK(index < array_buffer_contents_.length());
1684 *contents = array_buffer_contents_[index];
1685 // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter
1686 // our copy so it won't be double-free'd when this SerializationData is
1687 // destroyed.
1688 array_buffer_contents_[index] = ArrayBuffer::Contents();
1689}
1690
1691
1692void SerializationData::ReadSharedArrayBufferContents(
1693 SharedArrayBuffer::Contents* contents, int* offset) const {
1694 int index = Read<int>(offset);
1695 DCHECK(index < shared_array_buffer_contents_.length());
1696 *contents = shared_array_buffer_contents_[index];
1697}
1698
1699
1700void SerializationDataQueue::Enqueue(SerializationData* data) {
1701 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1702 data_.Add(data);
1703}
1704
1705
1706bool SerializationDataQueue::Dequeue(SerializationData** data) {
1707 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1708 *data = NULL;
1709 if (data_.is_empty()) return false;
1710 *data = data_.Remove(0);
1711 return true;
1712}
1713
1714
1715bool SerializationDataQueue::IsEmpty() {
1716 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1717 return data_.is_empty();
1718}
1719
1720
1721void SerializationDataQueue::Clear() {
1722 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1723 for (int i = 0; i < data_.length(); ++i) {
1724 delete data_[i];
1725 }
1726 data_.Clear();
1727}
1728
1729
1730Worker::Worker()
1731 : in_semaphore_(0),
1732 out_semaphore_(0),
1733 thread_(NULL),
1734 script_(NULL),
1735 running_(false) {}
1736
1737
1738Worker::~Worker() {
1739 delete thread_;
1740 thread_ = NULL;
1741 delete[] script_;
1742 script_ = NULL;
1743 in_queue_.Clear();
1744 out_queue_.Clear();
1745}
1746
1747
1748void Worker::StartExecuteInThread(const char* script) {
1749 running_ = true;
1750 script_ = i::StrDup(script);
1751 thread_ = new WorkerThread(this);
1752 thread_->Start();
1753}
1754
1755
1756void Worker::PostMessage(SerializationData* data) {
1757 in_queue_.Enqueue(data);
1758 in_semaphore_.Signal();
1759}
1760
1761
1762SerializationData* Worker::GetMessage() {
1763 SerializationData* data = NULL;
1764 while (!out_queue_.Dequeue(&data)) {
1765 // If the worker is no longer running, and there are no messages in the
1766 // queue, don't expect any more messages from it.
1767 if (!base::NoBarrier_Load(&running_)) break;
1768 out_semaphore_.Wait();
1769 }
1770 return data;
1771}
1772
1773
1774void Worker::Terminate() {
1775 base::NoBarrier_Store(&running_, false);
1776 // Post NULL to wake the Worker thread message loop, and tell it to stop
1777 // running.
1778 PostMessage(NULL);
1779}
1780
1781
1782void Worker::WaitForThread() {
1783 Terminate();
1784 thread_->Join();
1785}
1786
1787
1788void Worker::ExecuteInThread() {
1789 Isolate::CreateParams create_params;
1790 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1791 Isolate* isolate = Isolate::New(create_params);
1792 {
1793 Isolate::Scope iscope(isolate);
1794 {
1795 HandleScope scope(isolate);
1796 PerIsolateData data(isolate);
1797 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1798 {
1799 Context::Scope cscope(context);
1800 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1801
1802 Local<Object> global = context->Global();
1803 Local<Value> this_value = External::New(isolate, this);
1804 Local<FunctionTemplate> postmessage_fun_template =
1805 FunctionTemplate::New(isolate, PostMessageOut, this_value);
1806
1807 Local<Function> postmessage_fun;
1808 if (postmessage_fun_template->GetFunction(context)
1809 .ToLocal(&postmessage_fun)) {
1810 global->Set(context, String::NewFromUtf8(isolate, "postMessage",
1811 NewStringType::kNormal)
1812 .ToLocalChecked(),
1813 postmessage_fun).FromJust();
1814 }
1815
1816 // First run the script
1817 Local<String> file_name =
1818 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1819 .ToLocalChecked();
1820 Local<String> source =
1821 String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
1822 .ToLocalChecked();
1823 if (Shell::ExecuteString(isolate, source, file_name, false, true)) {
1824 // Get the message handler
1825 Local<Value> onmessage =
1826 global->Get(context, String::NewFromUtf8(isolate, "onmessage",
1827 NewStringType::kNormal)
1828 .ToLocalChecked()).ToLocalChecked();
1829 if (onmessage->IsFunction()) {
1830 Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
1831 // Now wait for messages
1832 while (true) {
1833 in_semaphore_.Wait();
1834 SerializationData* data;
1835 if (!in_queue_.Dequeue(&data)) continue;
1836 if (data == NULL) {
1837 break;
1838 }
1839 int offset = 0;
1840 Local<Value> data_value;
1841 if (Shell::DeserializeValue(isolate, *data, &offset)
1842 .ToLocal(&data_value)) {
1843 Local<Value> argv[] = {data_value};
1844 (void)onmessage_fun->Call(context, global, 1, argv);
1845 }
1846 delete data;
1847 }
1848 }
1849 }
1850 }
1851 }
1852 Shell::CollectGarbage(isolate);
1853 }
1854 isolate->Dispose();
1855
1856 // Post NULL to wake the thread waiting on GetMessage() if there is one.
1857 out_queue_.Enqueue(NULL);
1858 out_semaphore_.Signal();
1859}
1860
1861
1862void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
1863 Isolate* isolate = args.GetIsolate();
1864 HandleScope handle_scope(isolate);
1865
1866 if (args.Length() < 1) {
1867 Throw(isolate, "Invalid argument");
1868 return;
1869 }
1870
1871 Local<Value> message = args[0];
1872
1873 // TODO(binji): Allow transferring from worker to main thread?
1874 Shell::ObjectList to_transfer;
1875
1876 Shell::ObjectList seen_objects;
1877 SerializationData* data = new SerializationData;
1878 if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects,
1879 data)) {
1880 DCHECK(args.Data()->IsExternal());
1881 Local<External> this_value = Local<External>::Cast(args.Data());
1882 Worker* worker = static_cast<Worker*>(this_value->Value());
1883 worker->out_queue_.Enqueue(data);
1884 worker->out_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001885 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001886 delete data;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001887 }
1888}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001889#endif // !V8_SHARED
1890
1891
1892void SetFlagsFromString(const char* flags) {
1893 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
1894}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001895
1896
1897bool Shell::SetOptions(int argc, char* argv[]) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001898 bool logfile_per_isolate = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001899 for (int i = 0; i < argc; i++) {
1900 if (strcmp(argv[i], "--stress-opt") == 0) {
1901 options.stress_opt = true;
1902 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001903 } else if (strcmp(argv[i], "--nostress-opt") == 0) {
1904 options.stress_opt = false;
1905 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001906 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1907 options.stress_deopt = true;
1908 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001909 } else if (strcmp(argv[i], "--mock-arraybuffer-allocator") == 0) {
1910 options.mock_arraybuffer_allocator = true;
1911 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001912 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1913 // No support for stressing if we can't use --always-opt.
1914 options.stress_opt = false;
1915 options.stress_deopt = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001916 } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
1917 logfile_per_isolate = true;
1918 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001919 } else if (strcmp(argv[i], "--shell") == 0) {
1920 options.interactive_shell = true;
1921 argv[i] = NULL;
1922 } else if (strcmp(argv[i], "--test") == 0) {
1923 options.test_shell = true;
1924 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001925 } else if (strcmp(argv[i], "--notest") == 0 ||
1926 strcmp(argv[i], "--no-test") == 0) {
1927 options.test_shell = false;
1928 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001929 } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
1930 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001931 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001932 } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
1933 options.invoke_weak_callbacks = true;
1934 // TODO(jochen) See issue 3351
1935 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001936 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001937 } else if (strcmp(argv[i], "--omit-quit") == 0) {
1938 options.omit_quit = true;
1939 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001940 } else if (strcmp(argv[i], "-f") == 0) {
1941 // Ignore any -f flags for compatibility with other stand-alone
1942 // JavaScript engines.
1943 continue;
1944 } else if (strcmp(argv[i], "--isolate") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001945#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001946 printf("D8 with shared library does not support multi-threading\n");
1947 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001948#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001949 options.num_isolates++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001950 } else if (strcmp(argv[i], "--dump-heap-constants") == 0) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001951#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001952 printf("D8 with shared library does not support constant dumping\n");
Ben Murdoch589d6972011-11-30 16:04:58 +00001953 return false;
1954#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001955 options.dump_heap_constants = true;
1956 argv[i] = NULL;
Ben Murdoch589d6972011-11-30 16:04:58 +00001957#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001958 } else if (strcmp(argv[i], "--throws") == 0) {
1959 options.expected_to_throw = true;
1960 argv[i] = NULL;
1961 } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
1962 options.icu_data_file = argv[i] + 16;
1963 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001964#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001965 } else if (strcmp(argv[i], "--dump-counters") == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001966 printf("D8 with shared library does not include counters\n");
1967 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001968#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001969#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1970 } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
1971 options.natives_blob = argv[i] + 15;
1972 argv[i] = NULL;
1973 } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
1974 options.snapshot_blob = argv[i] + 16;
1975 argv[i] = NULL;
1976#endif // V8_USE_EXTERNAL_STARTUP_DATA
1977 } else if (strcmp(argv[i], "--cache") == 0 ||
1978 strncmp(argv[i], "--cache=", 8) == 0) {
1979 const char* value = argv[i] + 7;
1980 if (!*value || strncmp(value, "=code", 6) == 0) {
1981 options.compile_options = v8::ScriptCompiler::kProduceCodeCache;
1982 } else if (strncmp(value, "=parse", 7) == 0) {
1983 options.compile_options = v8::ScriptCompiler::kProduceParserCache;
1984 } else if (strncmp(value, "=none", 6) == 0) {
1985 options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
1986 } else {
1987 printf("Unknown option to --cache.\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001988 return false;
1989 }
1990 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001991 }
1992 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001993
1994 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1995
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001996 bool enable_harmony_modules = false;
1997
Ben Murdoch589d6972011-11-30 16:04:58 +00001998 // Set up isolated source groups.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001999 options.isolate_sources = new SourceGroup[options.num_isolates];
2000 SourceGroup* current = options.isolate_sources;
2001 current->Begin(argv, 1);
2002 for (int i = 1; i < argc; i++) {
2003 const char* str = argv[i];
2004 if (strcmp(str, "--isolate") == 0) {
2005 current->End(i);
2006 current++;
2007 current->Begin(argv, i + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002008 } else if (strcmp(str, "--module") == 0) {
2009 // Pass on to SourceGroup, which understands this option.
2010 enable_harmony_modules = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002011 } else if (strncmp(argv[i], "--", 2) == 0) {
2012 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002013 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
2014 options.script_executed = true;
2015 } else if (strncmp(str, "-", 1) != 0) {
2016 // Not a flag, so it must be a script to execute.
2017 options.script_executed = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002018 }
2019 }
2020 current->End(argc);
2021
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002022 if (!logfile_per_isolate && options.num_isolates) {
2023 SetFlagsFromString("--nologfile_per_isolate");
2024 }
2025
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002026 if (enable_harmony_modules) {
2027 SetFlagsFromString("--harmony-modules");
2028 }
2029
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002030 return true;
2031}
2032
2033
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002034int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002035#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002036 for (int i = 1; i < options.num_isolates; ++i) {
2037 options.isolate_sources[i].StartExecuteInThread();
2038 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002039#endif // !V8_SHARED
2040 {
2041 HandleScope scope(isolate);
2042 Local<Context> context = CreateEvaluationContext(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002043 if (last_run && options.use_interactive_shell()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002044 // Keep using the same context in the interactive shell.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002045 evaluation_context_.Reset(isolate, context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002046 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002047 {
2048 Context::Scope cscope(context);
2049 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2050 options.isolate_sources[0].Execute(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002051 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002052 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002053 CollectGarbage(isolate);
2054#ifndef V8_SHARED
2055 for (int i = 1; i < options.num_isolates; ++i) {
2056 if (last_run) {
2057 options.isolate_sources[i].JoinThread();
2058 } else {
2059 options.isolate_sources[i].WaitForThread();
2060 }
2061 }
2062 CleanupWorkers();
2063#endif // !V8_SHARED
2064 return 0;
2065}
2066
2067
2068void Shell::CollectGarbage(Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002069 if (options.send_idle_notification) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002070 const double kLongIdlePauseInSeconds = 1.0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002071 isolate->ContextDisposedNotification();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002072 isolate->IdleNotificationDeadline(
2073 g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002074 }
2075 if (options.invoke_weak_callbacks) {
2076 // By sending a low memory notifications, we will try hard to collect all
2077 // garbage and will therefore also invoke all weak callbacks of actually
2078 // unreachable persistent handles.
2079 isolate->LowMemoryNotification();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002080 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002081}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002082
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002083
2084void Shell::EmptyMessageQueues(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002085#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002086 if (!i::FLAG_verify_predictable) {
2087#endif
2088 while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue;
2089#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002090 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002091#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00002092}
2093
2094
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002095#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002096bool Shell::SerializeValue(Isolate* isolate, Local<Value> value,
2097 const ObjectList& to_transfer,
2098 ObjectList* seen_objects,
2099 SerializationData* out_data) {
2100 DCHECK(out_data);
2101 Local<Context> context = isolate->GetCurrentContext();
2102
2103 if (value->IsUndefined()) {
2104 out_data->WriteTag(kSerializationTagUndefined);
2105 } else if (value->IsNull()) {
2106 out_data->WriteTag(kSerializationTagNull);
2107 } else if (value->IsTrue()) {
2108 out_data->WriteTag(kSerializationTagTrue);
2109 } else if (value->IsFalse()) {
2110 out_data->WriteTag(kSerializationTagFalse);
2111 } else if (value->IsNumber()) {
2112 Local<Number> num = Local<Number>::Cast(value);
2113 double value = num->Value();
2114 out_data->WriteTag(kSerializationTagNumber);
2115 out_data->Write(value);
2116 } else if (value->IsString()) {
2117 v8::String::Utf8Value str(value);
2118 out_data->WriteTag(kSerializationTagString);
2119 out_data->Write(str.length());
2120 out_data->WriteMemory(*str, str.length());
2121 } else if (value->IsArray()) {
2122 Local<Array> array = Local<Array>::Cast(value);
2123 if (FindInObjectList(array, *seen_objects)) {
2124 Throw(isolate, "Duplicated arrays not supported");
2125 return false;
2126 }
2127 seen_objects->Add(array);
2128 out_data->WriteTag(kSerializationTagArray);
2129 uint32_t length = array->Length();
2130 out_data->Write(length);
2131 for (uint32_t i = 0; i < length; ++i) {
2132 Local<Value> element_value;
2133 if (array->Get(context, i).ToLocal(&element_value)) {
2134 if (!SerializeValue(isolate, element_value, to_transfer, seen_objects,
2135 out_data))
2136 return false;
2137 } else {
2138 Throw(isolate, "Failed to serialize array element.");
2139 return false;
2140 }
2141 }
2142 } else if (value->IsArrayBuffer()) {
2143 Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value);
2144 if (FindInObjectList(array_buffer, *seen_objects)) {
2145 Throw(isolate, "Duplicated array buffers not supported");
2146 return false;
2147 }
2148 seen_objects->Add(array_buffer);
2149 if (FindInObjectList(array_buffer, to_transfer)) {
2150 // Transfer ArrayBuffer
2151 if (!array_buffer->IsNeuterable()) {
2152 Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer");
2153 return false;
2154 }
2155
2156 ArrayBuffer::Contents contents = array_buffer->IsExternal()
2157 ? array_buffer->GetContents()
2158 : array_buffer->Externalize();
2159 array_buffer->Neuter();
2160 out_data->WriteArrayBufferContents(contents);
2161 } else {
2162 ArrayBuffer::Contents contents = array_buffer->GetContents();
2163 // Clone ArrayBuffer
2164 if (contents.ByteLength() > i::kMaxInt) {
2165 Throw(isolate, "ArrayBuffer is too big to clone");
2166 return false;
2167 }
2168
2169 int32_t byte_length = static_cast<int32_t>(contents.ByteLength());
2170 out_data->WriteTag(kSerializationTagArrayBuffer);
2171 out_data->Write(byte_length);
2172 out_data->WriteMemory(contents.Data(), byte_length);
2173 }
2174 } else if (value->IsSharedArrayBuffer()) {
2175 Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value);
2176 if (FindInObjectList(sab, *seen_objects)) {
2177 Throw(isolate, "Duplicated shared array buffers not supported");
2178 return false;
2179 }
2180 seen_objects->Add(sab);
2181 if (!FindInObjectList(sab, to_transfer)) {
2182 Throw(isolate, "SharedArrayBuffer must be transferred");
2183 return false;
2184 }
2185
2186 SharedArrayBuffer::Contents contents;
2187 if (sab->IsExternal()) {
2188 contents = sab->GetContents();
2189 } else {
2190 contents = sab->Externalize();
2191 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2192 externalized_shared_contents_.Add(contents);
2193 }
2194 out_data->WriteSharedArrayBufferContents(contents);
2195 } else if (value->IsObject()) {
2196 Local<Object> object = Local<Object>::Cast(value);
2197 if (FindInObjectList(object, *seen_objects)) {
2198 Throw(isolate, "Duplicated objects not supported");
2199 return false;
2200 }
2201 seen_objects->Add(object);
2202 Local<Array> property_names;
2203 if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
2204 Throw(isolate, "Unable to get property names");
2205 return false;
2206 }
2207
2208 uint32_t length = property_names->Length();
2209 out_data->WriteTag(kSerializationTagObject);
2210 out_data->Write(length);
2211 for (uint32_t i = 0; i < length; ++i) {
2212 Local<Value> name;
2213 Local<Value> property_value;
2214 if (property_names->Get(context, i).ToLocal(&name) &&
2215 object->Get(context, name).ToLocal(&property_value)) {
2216 if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data))
2217 return false;
2218 if (!SerializeValue(isolate, property_value, to_transfer, seen_objects,
2219 out_data))
2220 return false;
2221 } else {
2222 Throw(isolate, "Failed to serialize property.");
2223 return false;
2224 }
2225 }
2226 } else {
2227 Throw(isolate, "Don't know how to serialize object");
2228 return false;
2229 }
2230
2231 return true;
2232}
2233
2234
2235MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
2236 const SerializationData& data,
2237 int* offset) {
2238 DCHECK(offset);
2239 EscapableHandleScope scope(isolate);
2240 // This function should not use utility_context_ because it is running on a
2241 // different thread.
2242 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 Murdochb8a8cc12014-11-26 15:28:44 +00002432 v8::V8::InitializeICU(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#if !defined(V8_SHARED) && defined(ENABLE_GDB_JIT_INTERFACE)
2463 if (i::FLAG_gdbjit) {
2464 create_params.code_event_handler = i::GDBJITInterface::EventHandler;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002465 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002466#endif
2467#ifdef ENABLE_VTUNE_JIT_INTERFACE
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002468 create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002469#endif
2470#ifndef V8_SHARED
2471 create_params.constraints.ConfigureDefaults(
2472 base::SysInfo::AmountOfPhysicalMemory(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002473 base::SysInfo::AmountOfVirtualMemory());
2474
2475 Shell::counter_map_ = new CounterMap();
2476 if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
2477 create_params.counter_lookup_callback = LookupCounter;
2478 create_params.create_histogram_callback = CreateHistogram;
2479 create_params.add_histogram_sample_callback = AddHistogramSample;
2480 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002481#endif
2482 Isolate* isolate = Isolate::New(create_params);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002483 {
2484 Isolate::Scope scope(isolate);
2485 Initialize(isolate);
2486 PerIsolateData data(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002487
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002488#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002489 if (options.dump_heap_constants) {
2490 DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate));
2491 return 0;
2492 }
2493#endif
2494
2495 if (options.stress_opt || options.stress_deopt) {
2496 Testing::SetStressRunType(options.stress_opt
2497 ? Testing::kStressTypeOpt
2498 : Testing::kStressTypeDeopt);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002499 options.stress_runs = Testing::GetStressRuns();
2500 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2501 printf("============ Stress %d/%d ============\n", i + 1,
2502 options.stress_runs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002503 Testing::PrepareStressRun(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002504 bool last_run = i == options.stress_runs - 1;
2505 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002506 }
2507 printf("======== Full Deoptimization =======\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002508 Testing::DeoptimizeAll(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002509#if !defined(V8_SHARED)
2510 } else if (i::FLAG_stress_runs > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002511 options.stress_runs = i::FLAG_stress_runs;
2512 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2513 printf("============ Run %d/%d ============\n", i + 1,
2514 options.stress_runs);
2515 bool last_run = i == options.stress_runs - 1;
2516 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002517 }
2518#endif
2519 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002520 bool last_run = true;
2521 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002522 }
2523
2524 // Run interactive shell if explicitly requested or if no script has been
2525 // executed, but never on --test
2526 if (options.use_interactive_shell()) {
2527#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002528 InstallUtilityScript(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002529#endif // !V8_SHARED
2530 RunShell(isolate);
2531 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002532
2533 // Shut down contexts and collect garbage.
2534 evaluation_context_.Reset();
2535#ifndef V8_SHARED
2536 utility_context_.Reset();
2537#endif // !V8_SHARED
2538 CollectGarbage(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002539 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002540 OnExit(isolate);
2541#ifndef V8_SHARED
2542 // Dump basic block profiling data.
2543 if (i::BasicBlockProfiler* profiler =
2544 reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
2545 i::OFStream os(stdout);
2546 os << *profiler;
2547 }
2548#endif // !V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002549 isolate->Dispose();
2550 V8::Dispose();
2551 V8::ShutdownPlatform();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002552 delete g_platform;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002553
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002554 return result;
2555}
2556
Steve Blocka7e24c12009-10-30 11:49:00 +00002557} // namespace v8
2558
2559
Ben Murdoch257744e2011-11-30 15:57:28 +00002560#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +00002561int main(int argc, char* argv[]) {
2562 return v8::Shell::Main(argc, argv);
2563}
Ben Murdoch257744e2011-11-30 15:57:28 +00002564#endif