blob: 7c9a24f520e91f0a537c343a03d9734cae8b67f2 [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#ifdef ENABLE_VTUNE_JIT_INTERFACE
30#include "src/third_party/vtune/v8-vtune.h"
31#endif
32
33#include "src/d8.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010034#include "src/ostreams.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000035
36#include "include/libplatform/libplatform.h"
37#ifndef V8_SHARED
38#include "src/api.h"
39#include "src/base/cpu.h"
40#include "src/base/logging.h"
41#include "src/base/platform/platform.h"
42#include "src/base/sys-info.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040043#include "src/basic-block-profiler.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000044#include "src/snapshot/natives.h"
45#include "src/utils.h"
Ben Murdochb8a8cc12014-11-26 15:28:44 +000046#include "src/v8.h"
47#endif // !V8_SHARED
48
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000049#if !defined(_WIN32) && !defined(_WIN64)
50#include <unistd.h> // NOLINT
Ben Murdochb8a8cc12014-11-26 15:28:44 +000051#else
52#include <windows.h> // NOLINT
53#if defined(_MSC_VER)
54#include <crtdbg.h> // NOLINT
55#endif // defined(_MSC_VER)
56#endif // !defined(_WIN32) && !defined(_WIN64)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000057
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058#ifndef DCHECK
59#define DCHECK(condition) assert(condition)
Ben Murdoch69a99ed2011-11-30 16:03:39 +000060#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000061
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000062#ifndef CHECK
63#define CHECK(condition) assert(condition)
64#endif
65
Steve Blocka7e24c12009-10-30 11:49:00 +000066namespace v8 {
67
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000068namespace {
Steve Blocka7e24c12009-10-30 11:49:00 +000069
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000070const int MB = 1024 * 1024;
71#ifndef V8_SHARED
72const int kMaxWorkers = 50;
73#endif
74
75
76class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
77 public:
78 virtual void* Allocate(size_t length) {
79 void* data = AllocateUninitialized(length);
80 return data == NULL ? data : memset(data, 0, length);
81 }
82 virtual void* AllocateUninitialized(size_t length) { return malloc(length); }
83 virtual void Free(void* data, size_t) { free(data); }
84};
85
86
87class MockArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
88 public:
89 void* Allocate(size_t length) override {
90 size_t actual_length = length > 10 * MB ? 1 : length;
91 void* data = AllocateUninitialized(actual_length);
92 return data == NULL ? data : memset(data, 0, actual_length);
93 }
94 void* AllocateUninitialized(size_t length) override {
95 return length > 10 * MB ? malloc(1) : malloc(length);
96 }
97 void Free(void* p, size_t) override { free(p); }
98};
99
100
101#ifndef V8_SHARED
102// Predictable v8::Platform implementation. All background and foreground
103// tasks are run immediately, delayed tasks are not executed at all.
104class PredictablePlatform : public Platform {
105 public:
106 PredictablePlatform() {}
107
108 void CallOnBackgroundThread(Task* task,
109 ExpectedRuntime expected_runtime) override {
110 task->Run();
111 delete task;
112 }
113
114 void CallOnForegroundThread(v8::Isolate* isolate, Task* task) override {
115 task->Run();
116 delete task;
117 }
118
119 void CallDelayedOnForegroundThread(v8::Isolate* isolate, Task* task,
120 double delay_in_seconds) override {
121 delete task;
122 }
123
124 void CallIdleOnForegroundThread(v8::Isolate* isolate,
125 IdleTask* task) override {
126 UNREACHABLE();
127 }
128
129 bool IdleTasksEnabled(v8::Isolate* isolate) override { return false; }
130
131 double MonotonicallyIncreasingTime() override {
132 return synthetic_time_in_sec_ += 0.00001;
133 }
134
135 uint64_t AddTraceEvent(char phase, const uint8_t* categoryEnabledFlag,
136 const char* name, uint64_t id, uint64_t bind_id,
137 int numArgs, const char** argNames,
138 const uint8_t* argTypes, const uint64_t* argValues,
139 unsigned int flags) override {
140 return 0;
141 }
142
143 void UpdateTraceEventDuration(const uint8_t* categoryEnabledFlag,
144 const char* name, uint64_t handle) override {}
145
146 const uint8_t* GetCategoryGroupEnabled(const char* name) override {
147 static uint8_t no = 0;
148 return &no;
149 }
150
151 const char* GetCategoryGroupName(
152 const uint8_t* categoryEnabledFlag) override {
153 static const char* dummy = "dummy";
154 return dummy;
155 }
156
157 private:
158 double synthetic_time_in_sec_ = 0.0;
159
160 DISALLOW_COPY_AND_ASSIGN(PredictablePlatform);
161};
162#endif // !V8_SHARED
163
164
165v8::Platform* g_platform = NULL;
166
167
168static Local<Value> Throw(Isolate* isolate, const char* message) {
169 return isolate->ThrowException(
170 String::NewFromUtf8(isolate, message, NewStringType::kNormal)
171 .ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000172}
173
174
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000175#ifndef V8_SHARED
176bool FindInObjectList(Local<Object> object, const Shell::ObjectList& list) {
177 for (int i = 0; i < list.length(); ++i) {
178 if (list[i]->StrictEquals(object)) {
179 return true;
180 }
181 }
182 return false;
183}
184
185
186Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
187 if (object->InternalFieldCount() != 1) {
188 Throw(isolate, "this is not a Worker");
189 return NULL;
190 }
191
192 Worker* worker =
193 static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0));
194 if (worker == NULL) {
195 Throw(isolate, "Worker is defunct because main thread is terminating");
196 return NULL;
197 }
198
199 return worker;
200}
201#endif // !V8_SHARED
202
203
204} // namespace
205
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000206
207class PerIsolateData {
208 public:
209 explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
210 HandleScope scope(isolate);
211 isolate->SetData(0, this);
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000213
214 ~PerIsolateData() {
215 isolate_->SetData(0, NULL); // Not really needed, just to be sure...
216 }
217
218 inline static PerIsolateData* Get(Isolate* isolate) {
219 return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
220 }
221
222 class RealmScope {
223 public:
224 explicit RealmScope(PerIsolateData* data);
225 ~RealmScope();
226 private:
227 PerIsolateData* data_;
228 };
229
230 private:
231 friend class Shell;
232 friend class RealmScope;
233 Isolate* isolate_;
234 int realm_count_;
235 int realm_current_;
236 int realm_switch_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000237 Global<Context>* realms_;
238 Global<Value> realm_shared_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239
240 int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
241 int arg_offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000242 int RealmFind(Local<Context> context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000243};
244
245
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100246#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000247CounterMap* Shell::counter_map_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000248base::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000249CounterCollection Shell::local_counters_;
250CounterCollection* Shell::counters_ = &local_counters_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000251base::LazyMutex Shell::context_mutex_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000252const base::TimeTicks Shell::kInitialTicks =
253 base::TimeTicks::HighResolutionNow();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000254Global<Context> Shell::utility_context_;
255base::LazyMutex Shell::workers_mutex_;
256bool Shell::allow_new_workers_ = true;
257i::List<Worker*> Shell::workers_;
258i::List<SharedArrayBuffer::Contents> Shell::externalized_shared_contents_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000259#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000260
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000261Global<Context> Shell::evaluation_context_;
262ArrayBuffer::Allocator* Shell::array_buffer_allocator;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000263ShellOptions Shell::options;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264base::OnceType Shell::quit_once_ = V8_ONCE_INIT;
Steve Blocka7e24c12009-10-30 11:49:00 +0000265
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000266#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000267bool CounterMap::Match(void* key1, void* key2) {
268 const char* name1 = reinterpret_cast<const char*>(key1);
269 const char* name2 = reinterpret_cast<const char*>(key2);
270 return strcmp(name1, name2) == 0;
271}
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000272#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000273
274
275// Converts a V8 value to a C string.
Steve Block6ded16b2010-05-10 14:33:55 +0100276const char* Shell::ToCString(const v8::String::Utf8Value& value) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000277 return *value ? *value : "<string conversion failed>";
278}
279
280
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400281ScriptCompiler::CachedData* CompileForCachedData(
282 Local<String> source, Local<Value> name,
283 ScriptCompiler::CompileOptions compile_options) {
284 int source_length = source->Length();
285 uint16_t* source_buffer = new uint16_t[source_length];
286 source->Write(source_buffer, 0, source_length);
287 int name_length = 0;
288 uint16_t* name_buffer = NULL;
289 if (name->IsString()) {
290 Local<String> name_string = Local<String>::Cast(name);
291 name_length = name_string->Length();
292 name_buffer = new uint16_t[name_length];
293 name_string->Write(name_buffer, 0, name_length);
294 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000295 Isolate::CreateParams create_params;
296 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
297 Isolate* temp_isolate = Isolate::New(create_params);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400298 ScriptCompiler::CachedData* result = NULL;
299 {
300 Isolate::Scope isolate_scope(temp_isolate);
301 HandleScope handle_scope(temp_isolate);
302 Context::Scope context_scope(Context::New(temp_isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000303 Local<String> source_copy =
304 v8::String::NewFromTwoByte(temp_isolate, source_buffer,
305 v8::NewStringType::kNormal,
306 source_length).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400307 Local<Value> name_copy;
308 if (name_buffer) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000309 name_copy = v8::String::NewFromTwoByte(temp_isolate, name_buffer,
310 v8::NewStringType::kNormal,
311 name_length).ToLocalChecked();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400312 } else {
313 name_copy = v8::Undefined(temp_isolate);
314 }
315 ScriptCompiler::Source script_source(source_copy, ScriptOrigin(name_copy));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000316 if (!ScriptCompiler::CompileUnboundScript(temp_isolate, &script_source,
317 compile_options).IsEmpty() &&
318 script_source.GetCachedData()) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400319 int length = script_source.GetCachedData()->length;
320 uint8_t* cache = new uint8_t[length];
321 memcpy(cache, script_source.GetCachedData()->data, length);
322 result = new ScriptCompiler::CachedData(
323 cache, length, ScriptCompiler::CachedData::BufferOwned);
324 }
325 }
326 temp_isolate->Dispose();
327 delete[] source_buffer;
328 delete[] name_buffer;
329 return result;
330}
331
332
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000333// Compile a string within the current v8 context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334MaybeLocal<Script> Shell::CompileString(
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000335 Isolate* isolate, Local<String> source, Local<Value> name,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336 ScriptCompiler::CompileOptions compile_options, SourceType source_type) {
337 Local<Context> context(isolate->GetCurrentContext());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000338 ScriptOrigin origin(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400339 if (compile_options == ScriptCompiler::kNoCompileOptions) {
340 ScriptCompiler::Source script_source(source, origin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000341 return source_type == SCRIPT
342 ? ScriptCompiler::Compile(context, &script_source,
343 compile_options)
344 : ScriptCompiler::CompileModule(context, &script_source,
345 compile_options);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000346 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400347
348 ScriptCompiler::CachedData* data =
349 CompileForCachedData(source, name, compile_options);
350 ScriptCompiler::Source cached_source(source, origin, data);
351 if (compile_options == ScriptCompiler::kProduceCodeCache) {
352 compile_options = ScriptCompiler::kConsumeCodeCache;
353 } else if (compile_options == ScriptCompiler::kProduceParserCache) {
354 compile_options = ScriptCompiler::kConsumeParserCache;
355 } else {
356 DCHECK(false); // A new compile option?
357 }
358 if (data == NULL) compile_options = ScriptCompiler::kNoCompileOptions;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000359 MaybeLocal<Script> result =
360 source_type == SCRIPT
361 ? ScriptCompiler::Compile(context, &cached_source, compile_options)
362 : ScriptCompiler::CompileModule(context, &cached_source,
363 compile_options);
364 CHECK(data == NULL || !data->rejected);
365 return result;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000366}
367
368
Steve Blocka7e24c12009-10-30 11:49:00 +0000369// Executes a string within the current v8 context.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000370bool Shell::ExecuteString(Isolate* isolate, Local<String> source,
371 Local<Value> name, bool print_result,
372 bool report_exceptions, SourceType source_type) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000373 HandleScope handle_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000374 TryCatch try_catch(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100375 try_catch.SetVerbose(true);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000376
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000377 MaybeLocal<Value> maybe_result;
378 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000379 PerIsolateData* data = PerIsolateData::Get(isolate);
380 Local<Context> realm =
381 Local<Context>::New(isolate, data->realms_[data->realm_current_]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 Context::Scope context_scope(realm);
383 Local<Script> script;
384 if (!Shell::CompileString(isolate, source, name, options.compile_options,
385 source_type).ToLocal(&script)) {
386 // Print errors that happened during compilation.
387 if (report_exceptions) ReportException(isolate, &try_catch);
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 return false;
Steve Blocka7e24c12009-10-30 11:49:00 +0000389 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390 maybe_result = script->Run(realm);
391 EmptyMessageQueues(isolate);
392 data->realm_current_ = data->realm_switch_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000393 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000394 Local<Value> result;
395 if (!maybe_result.ToLocal(&result)) {
396 DCHECK(try_catch.HasCaught());
397 // Print errors that happened during execution.
398 if (report_exceptions) ReportException(isolate, &try_catch);
399 return false;
400 }
401 DCHECK(!try_catch.HasCaught());
402 if (print_result) {
403#if !defined(V8_SHARED)
404 if (options.test_shell) {
405#endif
406 if (!result->IsUndefined()) {
407 // If all went well and the result wasn't undefined then print
408 // the returned value.
409 v8::String::Utf8Value str(result);
410 fwrite(*str, sizeof(**str), str.length(), stdout);
411 printf("\n");
412 }
413#if !defined(V8_SHARED)
414 } else {
415 v8::TryCatch try_catch(isolate);
416 v8::Local<v8::Context> context =
417 v8::Local<v8::Context>::New(isolate, utility_context_);
418 v8::Context::Scope context_scope(context);
419 Local<Object> global = context->Global();
420 Local<Value> fun =
421 global->Get(context, String::NewFromUtf8(isolate, "Stringify",
422 v8::NewStringType::kNormal)
423 .ToLocalChecked()).ToLocalChecked();
424 Local<Value> argv[1] = {result};
425 Local<Value> s;
426 if (!Local<Function>::Cast(fun)
427 ->Call(context, global, 1, argv)
428 .ToLocal(&s)) {
429 return true;
430 }
431 DCHECK(!try_catch.HasCaught());
432 v8::String::Utf8Value str(s);
433 fwrite(*str, sizeof(**str), str.length(), stdout);
434 printf("\n");
435 }
436#endif
437 }
438 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000439}
440
441
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000442PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
443 data_->realm_count_ = 1;
444 data_->realm_current_ = 0;
445 data_->realm_switch_ = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000446 data_->realms_ = new Global<Context>[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000447 data_->realms_[0].Reset(data_->isolate_,
448 data_->isolate_->GetEnteredContext());
Steve Blocka7e24c12009-10-30 11:49:00 +0000449}
450
451
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000452PerIsolateData::RealmScope::~RealmScope() {
453 // Drop realms to avoid keeping them alive.
454 for (int i = 0; i < data_->realm_count_; ++i)
455 data_->realms_[i].Reset();
456 delete[] data_->realms_;
457 if (!data_->realm_shared_.IsEmpty())
458 data_->realm_shared_.Reset();
459}
460
461
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462int PerIsolateData::RealmFind(Local<Context> context) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000463 for (int i = 0; i < realm_count_; ++i) {
464 if (realms_[i] == context) return i;
465 }
466 return -1;
467}
468
469
470int PerIsolateData::RealmIndexOrThrow(
471 const v8::FunctionCallbackInfo<v8::Value>& args,
472 int arg_offset) {
473 if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
474 Throw(args.GetIsolate(), "Invalid argument");
475 return -1;
476 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 int index = args[arg_offset]
478 ->Int32Value(args.GetIsolate()->GetCurrentContext())
479 .FromMaybe(-1);
480 if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000481 Throw(args.GetIsolate(), "Invalid realm index");
482 return -1;
483 }
484 return index;
485}
486
487
488#ifndef V8_SHARED
489// performance.now() returns a time stamp as double, measured in milliseconds.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000490// When FLAG_verify_predictable mode is enabled it returns result of
491// v8::Platform::MonotonicallyIncreasingTime().
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000492void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
493 if (i::FLAG_verify_predictable) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000494 args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000495 } else {
496 base::TimeDelta delta =
497 base::TimeTicks::HighResolutionNow() - kInitialTicks;
498 args.GetReturnValue().Set(delta.InMillisecondsF());
499 }
500}
501#endif // !V8_SHARED
502
503
504// Realm.current() returns the index of the currently active realm.
505void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
506 Isolate* isolate = args.GetIsolate();
507 PerIsolateData* data = PerIsolateData::Get(isolate);
508 int index = data->RealmFind(isolate->GetEnteredContext());
509 if (index == -1) return;
510 args.GetReturnValue().Set(index);
511}
512
513
514// Realm.owner(o) returns the index of the realm that created o.
515void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
516 Isolate* isolate = args.GetIsolate();
517 PerIsolateData* data = PerIsolateData::Get(isolate);
518 if (args.Length() < 1 || !args[0]->IsObject()) {
519 Throw(args.GetIsolate(), "Invalid argument");
520 return;
521 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000522 int index = data->RealmFind(args[0]
523 ->ToObject(isolate->GetCurrentContext())
524 .ToLocalChecked()
525 ->CreationContext());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000526 if (index == -1) return;
527 args.GetReturnValue().Set(index);
528}
529
530
531// Realm.global(i) returns the global object of realm i.
532// (Note that properties of global objects cannot be read/written cross-realm.)
533void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
534 PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
535 int index = data->RealmIndexOrThrow(args, 0);
536 if (index == -1) return;
537 args.GetReturnValue().Set(
538 Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
539}
540
541
542// Realm.create() creates a new realm and returns its index.
543void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
544 Isolate* isolate = args.GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000545 TryCatch try_catch(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000546 PerIsolateData* data = PerIsolateData::Get(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000547 Global<Context>* old_realms = data->realms_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000548 int index = data->realm_count_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000549 data->realms_ = new Global<Context>[++data->realm_count_];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000550 for (int i = 0; i < index; ++i) {
551 data->realms_[i].Reset(isolate, old_realms[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552 old_realms[i].Reset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000553 }
554 delete[] old_realms;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000555 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
556 Local<Context> context = Context::New(isolate, NULL, global_template);
557 if (context.IsEmpty()) {
558 DCHECK(try_catch.HasCaught());
559 try_catch.ReThrow();
560 return;
561 }
562 data->realms_[index].Reset(isolate, context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000563 args.GetReturnValue().Set(index);
564}
565
566
567// Realm.dispose(i) disposes the reference to the realm i.
568void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
569 Isolate* isolate = args.GetIsolate();
570 PerIsolateData* data = PerIsolateData::Get(isolate);
571 int index = data->RealmIndexOrThrow(args, 0);
572 if (index == -1) return;
573 if (index == 0 ||
574 index == data->realm_current_ || index == data->realm_switch_) {
575 Throw(args.GetIsolate(), "Invalid realm index");
576 return;
577 }
578 data->realms_[index].Reset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000579 isolate->ContextDisposedNotification();
580 isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000581}
582
583
584// Realm.switch(i) switches to the realm i for consecutive interactive inputs.
585void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
586 Isolate* isolate = args.GetIsolate();
587 PerIsolateData* data = PerIsolateData::Get(isolate);
588 int index = data->RealmIndexOrThrow(args, 0);
589 if (index == -1) return;
590 data->realm_switch_ = index;
591}
592
593
594// Realm.eval(i, s) evaluates s in realm i and returns the result.
595void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
596 Isolate* isolate = args.GetIsolate();
597 PerIsolateData* data = PerIsolateData::Get(isolate);
598 int index = data->RealmIndexOrThrow(args, 0);
599 if (index == -1) return;
600 if (args.Length() < 2 || !args[1]->IsString()) {
601 Throw(args.GetIsolate(), "Invalid argument");
602 return;
603 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604 ScriptCompiler::Source script_source(
605 args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
606 Local<UnboundScript> script;
607 if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
608 .ToLocal(&script)) {
609 return;
610 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000611 Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
612 realm->Enter();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000613 Local<Value> result;
614 if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
615 realm->Exit();
616 return;
617 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000618 realm->Exit();
619 args.GetReturnValue().Set(result);
620}
621
622
623// Realm.shared is an accessor for a single shared value across realms.
624void Shell::RealmSharedGet(Local<String> property,
625 const PropertyCallbackInfo<Value>& info) {
626 Isolate* isolate = info.GetIsolate();
627 PerIsolateData* data = PerIsolateData::Get(isolate);
628 if (data->realm_shared_.IsEmpty()) return;
629 info.GetReturnValue().Set(data->realm_shared_);
630}
631
632void Shell::RealmSharedSet(Local<String> property,
633 Local<Value> value,
634 const PropertyCallbackInfo<void>& info) {
635 Isolate* isolate = info.GetIsolate();
636 PerIsolateData* data = PerIsolateData::Get(isolate);
637 data->realm_shared_.Reset(isolate, value);
638}
639
640
641void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
642 Write(args);
643 printf("\n");
644 fflush(stdout);
645}
646
647
648void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000649 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000650 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000651 if (i != 0) {
652 printf(" ");
653 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000654
655 // Explicitly catch potential exceptions in toString().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000656 v8::TryCatch try_catch(args.GetIsolate());
657 Local<Value> arg = args[i];
658 Local<String> str_obj;
659
660 if (arg->IsSymbol()) {
661 arg = Local<Symbol>::Cast(arg)->Name();
662 }
663 if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
664 .ToLocal(&str_obj)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665 try_catch.ReThrow();
666 return;
667 }
668
669 v8::String::Utf8Value str(str_obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000670 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
Steve Blockd0582a62009-12-15 09:54:21 +0000671 if (n != str.length()) {
672 printf("Error in fwrite\n");
Ben Murdoch589d6972011-11-30 16:04:58 +0000673 Exit(1);
Steve Blockd0582a62009-12-15 09:54:21 +0000674 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000675 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000676}
677
678
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000679void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000680 String::Utf8Value file(args[0]);
681 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000682 Throw(args.GetIsolate(), "Error loading file");
683 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000684 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000685 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000686 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000687 Throw(args.GetIsolate(), "Error loading file");
688 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000689 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000690 args.GetReturnValue().Set(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000691}
692
693
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000694Local<String> Shell::ReadFromStdin(Isolate* isolate) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000695 static const int kBufferSize = 256;
696 char buffer[kBufferSize];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000697 Local<String> accumulator =
698 String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000699 int length;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000700 while (true) {
701 // Continue reading if the line ends with an escape '\\' or the line has
702 // not been fully read into the buffer yet (does not end with '\n').
703 // If fgets gets an error, just give up.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100704 char* input = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000705 input = fgets(buffer, kBufferSize, stdin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000706 if (input == NULL) return Local<String>();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000707 length = static_cast<int>(strlen(buffer));
708 if (length == 0) {
709 return accumulator;
710 } else if (buffer[length-1] != '\n') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000711 accumulator = String::Concat(
712 accumulator,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000713 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
714 .ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000715 } else if (length > 1 && buffer[length-2] == '\\') {
716 buffer[length-2] = '\n';
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000717 accumulator = String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000718 accumulator,
719 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
720 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000721 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000722 return String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000723 accumulator,
724 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
725 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000726 }
727 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000728}
729
730
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000731void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000732 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000733 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 String::Utf8Value file(args[i]);
735 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000736 Throw(args.GetIsolate(), "Error loading file");
737 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000738 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000739 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000740 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000741 Throw(args.GetIsolate(), "Error loading file");
742 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000743 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000744 if (!ExecuteString(
745 args.GetIsolate(), source,
746 String::NewFromUtf8(args.GetIsolate(), *file,
747 NewStringType::kNormal).ToLocalChecked(),
748 false, true)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000749 Throw(args.GetIsolate(), "Error executing file");
750 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000751 }
752 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100753}
754
755
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000756#ifndef V8_SHARED
757void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
758 Isolate* isolate = args.GetIsolate();
759 HandleScope handle_scope(isolate);
760 if (args.Length() < 1 || !args[0]->IsString()) {
761 Throw(args.GetIsolate(), "1st argument must be string");
762 return;
763 }
764
765 if (!args.IsConstructCall()) {
766 Throw(args.GetIsolate(), "Worker must be constructed with new");
767 return;
768 }
769
770 {
771 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
772 if (workers_.length() >= kMaxWorkers) {
773 Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
774 return;
775 }
776
777 // Initialize the internal field to NULL; if we return early without
778 // creating a new Worker (because the main thread is terminating) we can
779 // early-out from the instance calls.
780 args.Holder()->SetAlignedPointerInInternalField(0, NULL);
781
782 if (!allow_new_workers_) return;
783
784 Worker* worker = new Worker;
785 args.Holder()->SetAlignedPointerInInternalField(0, worker);
786 workers_.Add(worker);
787
788 String::Utf8Value script(args[0]);
789 if (!*script) {
790 Throw(args.GetIsolate(), "Can't get worker script");
791 return;
792 }
793 worker->StartExecuteInThread(*script);
794 }
795}
796
797
798void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
799 Isolate* isolate = args.GetIsolate();
800 HandleScope handle_scope(isolate);
801 Local<Context> context = isolate->GetCurrentContext();
802
803 if (args.Length() < 1) {
804 Throw(isolate, "Invalid argument");
805 return;
806 }
807
808 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
809 if (!worker) {
810 return;
811 }
812
813 Local<Value> message = args[0];
814 ObjectList to_transfer;
815 if (args.Length() >= 2) {
816 if (!args[1]->IsArray()) {
817 Throw(isolate, "Transfer list must be an Array");
818 return;
819 }
820
821 Local<Array> transfer = Local<Array>::Cast(args[1]);
822 uint32_t length = transfer->Length();
823 for (uint32_t i = 0; i < length; ++i) {
824 Local<Value> element;
825 if (transfer->Get(context, i).ToLocal(&element)) {
826 if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) {
827 Throw(isolate,
828 "Transfer array elements must be an ArrayBuffer or "
829 "SharedArrayBuffer.");
830 break;
831 }
832
833 to_transfer.Add(Local<Object>::Cast(element));
834 }
835 }
836 }
837
838 ObjectList seen_objects;
839 SerializationData* data = new SerializationData;
840 if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) {
841 worker->PostMessage(data);
842 } else {
843 delete data;
844 }
845}
846
847
848void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
849 Isolate* isolate = args.GetIsolate();
850 HandleScope handle_scope(isolate);
851 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
852 if (!worker) {
853 return;
854 }
855
856 SerializationData* data = worker->GetMessage();
857 if (data) {
858 int offset = 0;
859 Local<Value> data_value;
860 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
861 args.GetReturnValue().Set(data_value);
862 }
863 delete data;
864 }
865}
866
867
868void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
869 Isolate* isolate = args.GetIsolate();
870 HandleScope handle_scope(isolate);
871 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
872 if (!worker) {
873 return;
874 }
875
876 worker->Terminate();
877}
878#endif // !V8_SHARED
879
880
881void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
882 int exit_code = (*args)[0]
883 ->Int32Value(args->GetIsolate()->GetCurrentContext())
884 .FromMaybe(0);
885#ifndef V8_SHARED
886 CleanupWorkers();
887#endif // !V8_SHARED
888 OnExit(args->GetIsolate());
889 Exit(exit_code);
890}
891
892
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000893void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000894 base::CallOnce(&quit_once_, &QuitOnce,
895 const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
Steve Blocka7e24c12009-10-30 11:49:00 +0000896}
897
898
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000899void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
900 args.GetReturnValue().Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000901 String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
902 NewStringType::kNormal).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000903}
904
905
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000906void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
907 HandleScope handle_scope(isolate);
908#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000909 Local<Context> utility_context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000910 bool enter_context = !isolate->InContext();
911 if (enter_context) {
912 utility_context = Local<Context>::New(isolate, utility_context_);
913 utility_context->Enter();
914 }
915#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000916 v8::String::Utf8Value exception(try_catch->Exception());
917 const char* exception_string = ToCString(exception);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000918 Local<Message> message = try_catch->Message();
Steve Blocka7e24c12009-10-30 11:49:00 +0000919 if (message.IsEmpty()) {
920 // V8 didn't provide any extra information about this error; just
921 // print the exception.
922 printf("%s\n", exception_string);
923 } else {
924 // Print (filename):(line number): (message).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000925 v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
Steve Blocka7e24c12009-10-30 11:49:00 +0000926 const char* filename_string = ToCString(filename);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000927 int linenum =
928 message->GetLineNumber(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000929 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
930 // Print line of source code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000931 v8::String::Utf8Value sourceline(
932 message->GetSourceLine(isolate->GetCurrentContext()).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 const char* sourceline_string = ToCString(sourceline);
934 printf("%s\n", sourceline_string);
935 // Print wavy underline (GetUnderline is deprecated).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000936 int start =
937 message->GetStartColumn(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000938 for (int i = 0; i < start; i++) {
939 printf(" ");
940 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000941 int end = message->GetEndColumn(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000942 for (int i = start; i < end; i++) {
943 printf("^");
944 }
945 printf("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000946 Local<Value> stack_trace_string;
947 if (try_catch->StackTrace(isolate->GetCurrentContext())
948 .ToLocal(&stack_trace_string) &&
949 stack_trace_string->IsString()) {
950 v8::String::Utf8Value stack_trace(
951 Local<String>::Cast(stack_trace_string));
952 printf("%s\n", ToCString(stack_trace));
Ben Murdoch257744e2011-11-30 15:57:28 +0000953 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000954 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000955 printf("\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000956#ifndef V8_SHARED
957 if (enter_context) utility_context->Exit();
958#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000959}
960
961
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000962#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000963int32_t* Counter::Bind(const char* name, bool is_histogram) {
964 int i;
965 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
966 name_[i] = static_cast<char>(name[i]);
967 name_[i] = '\0';
968 is_histogram_ = is_histogram;
969 return ptr();
970}
971
972
973void Counter::AddSample(int32_t sample) {
974 count_++;
975 sample_total_ += sample;
976}
977
978
979CounterCollection::CounterCollection() {
980 magic_number_ = 0xDEADFACE;
981 max_counters_ = kMaxCounters;
982 max_name_size_ = Counter::kMaxNameSize;
983 counters_in_use_ = 0;
984}
985
986
987Counter* CounterCollection::GetNextCounter() {
988 if (counters_in_use_ == kMaxCounters) return NULL;
989 return &counters_[counters_in_use_++];
990}
991
992
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000993void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
994 counters_file_ = base::OS::MemoryMappedFile::create(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000995 name, sizeof(CounterCollection), &local_counters_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000996 void* memory = (counters_file_ == NULL) ?
997 NULL : counters_file_->memory();
998 if (memory == NULL) {
999 printf("Could not map counters file %s\n", name);
Ben Murdoch589d6972011-11-30 16:04:58 +00001000 Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001001 }
1002 counters_ = static_cast<CounterCollection*>(memory);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001003 isolate->SetCounterFunction(LookupCounter);
1004 isolate->SetCreateHistogramFunction(CreateHistogram);
1005 isolate->SetAddHistogramSampleFunction(AddHistogramSample);
Steve Blocka7e24c12009-10-30 11:49:00 +00001006}
1007
1008
1009int CounterMap::Hash(const char* name) {
1010 int h = 0;
1011 int c;
1012 while ((c = *name++) != 0) {
1013 h += h << 5;
1014 h += c;
1015 }
1016 return h;
1017}
1018
1019
1020Counter* Shell::GetCounter(const char* name, bool is_histogram) {
1021 Counter* counter = counter_map_->Lookup(name);
1022
1023 if (counter == NULL) {
1024 counter = counters_->GetNextCounter();
1025 if (counter != NULL) {
1026 counter_map_->Set(name, counter);
1027 counter->Bind(name, is_histogram);
1028 }
1029 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001030 DCHECK(counter->is_histogram() == is_histogram);
Steve Blocka7e24c12009-10-30 11:49:00 +00001031 }
1032 return counter;
1033}
1034
1035
1036int* Shell::LookupCounter(const char* name) {
1037 Counter* counter = GetCounter(name, false);
1038
1039 if (counter != NULL) {
1040 return counter->ptr();
1041 } else {
1042 return NULL;
1043 }
1044}
1045
1046
1047void* Shell::CreateHistogram(const char* name,
1048 int min,
1049 int max,
1050 size_t buckets) {
1051 return GetCounter(name, true);
1052}
1053
1054
1055void Shell::AddHistogramSample(void* histogram, int sample) {
1056 Counter* counter = reinterpret_cast<Counter*>(histogram);
1057 counter->AddSample(sample);
1058}
1059
1060
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001061class NoUseStrongForUtilityScriptScope {
1062 public:
1063 NoUseStrongForUtilityScriptScope() : flag_(i::FLAG_use_strong) {
1064 i::FLAG_use_strong = false;
1065 }
1066 ~NoUseStrongForUtilityScriptScope() { i::FLAG_use_strong = flag_; }
1067
1068 private:
1069 bool flag_;
1070};
1071
1072
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001073void Shell::InstallUtilityScript(Isolate* isolate) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001074 NoUseStrongForUtilityScriptScope no_use_strong;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001075 HandleScope scope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001076 // If we use the utility context, we have to set the security tokens so that
1077 // utility, evaluation and debug context can all access each other.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001078 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
1079 utility_context_.Reset(isolate, Context::New(isolate, NULL, global_template));
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001080 v8::Local<v8::Context> utility_context =
1081 v8::Local<v8::Context>::New(isolate, utility_context_);
1082 v8::Local<v8::Context> evaluation_context =
1083 v8::Local<v8::Context>::New(isolate, evaluation_context_);
1084 utility_context->SetSecurityToken(Undefined(isolate));
1085 evaluation_context->SetSecurityToken(Undefined(isolate));
1086 v8::Context::Scope context_scope(utility_context);
Steve Blocka7e24c12009-10-30 11:49:00 +00001087
Steve Blocka7e24c12009-10-30 11:49:00 +00001088 // Run the d8 shell utility script in the utility context
1089 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001090 i::Vector<const char> shell_source =
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001091 i::NativesCollection<i::D8>::GetScriptSource(source_index);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001092 i::Vector<const char> shell_source_name =
1093 i::NativesCollection<i::D8>::GetScriptName(source_index);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001094 Local<String> source =
1095 String::NewFromUtf8(isolate, shell_source.start(), NewStringType::kNormal,
1096 shell_source.length()).ToLocalChecked();
1097 Local<String> name =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001098 String::NewFromUtf8(isolate, shell_source_name.start(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001099 NewStringType::kNormal,
1100 shell_source_name.length()).ToLocalChecked();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001101 ScriptOrigin origin(name);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001102 Local<Script> script =
1103 Script::Compile(utility_context, source, &origin).ToLocalChecked();
1104 script->Run(utility_context).ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001105 // Mark the d8 shell script as native to avoid it showing up as normal source
1106 // in the debugger.
Steve Block6ded16b2010-05-10 14:33:55 +01001107 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
1108 i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
1109 ? i::Handle<i::Script>(i::Script::cast(
1110 i::JSFunction::cast(*compiled_script)->shared()->script()))
1111 : i::Handle<i::Script>(i::Script::cast(
1112 i::SharedFunctionInfo::cast(*compiled_script)->script()));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001113 script_object->set_type(i::Script::TYPE_EXTENSION);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001114}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001115#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001116
1117
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001118Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
1119 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
1120 global_template->Set(
1121 String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
1122 .ToLocalChecked(),
1123 FunctionTemplate::New(isolate, Print));
1124 global_template->Set(
1125 String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
1126 .ToLocalChecked(),
1127 FunctionTemplate::New(isolate, Write));
1128 global_template->Set(
1129 String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
1130 .ToLocalChecked(),
1131 FunctionTemplate::New(isolate, Read));
1132 global_template->Set(
1133 String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
1134 .ToLocalChecked(),
1135 FunctionTemplate::New(isolate, ReadBuffer));
1136 global_template->Set(
1137 String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
1138 .ToLocalChecked(),
1139 FunctionTemplate::New(isolate, ReadLine));
1140 global_template->Set(
1141 String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
1142 .ToLocalChecked(),
1143 FunctionTemplate::New(isolate, Load));
1144 // Some Emscripten-generated code tries to call 'quit', which in turn would
1145 // call C's exit(). This would lead to memory leaks, because there is no way
1146 // we can terminate cleanly then, so we need a way to hide 'quit'.
1147 if (!options.omit_quit) {
1148 global_template->Set(
1149 String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
1150 .ToLocalChecked(),
1151 FunctionTemplate::New(isolate, Quit));
1152 }
1153 global_template->Set(
1154 String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
1155 .ToLocalChecked(),
1156 FunctionTemplate::New(isolate, Version));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001157
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001158 // Bind the Realm object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001159 Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
1160 realm_template->Set(
1161 String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
1162 .ToLocalChecked(),
1163 FunctionTemplate::New(isolate, RealmCurrent));
1164 realm_template->Set(
1165 String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
1166 .ToLocalChecked(),
1167 FunctionTemplate::New(isolate, RealmOwner));
1168 realm_template->Set(
1169 String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1170 .ToLocalChecked(),
1171 FunctionTemplate::New(isolate, RealmGlobal));
1172 realm_template->Set(
1173 String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
1174 .ToLocalChecked(),
1175 FunctionTemplate::New(isolate, RealmCreate));
1176 realm_template->Set(
1177 String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
1178 .ToLocalChecked(),
1179 FunctionTemplate::New(isolate, RealmDispose));
1180 realm_template->Set(
1181 String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
1182 .ToLocalChecked(),
1183 FunctionTemplate::New(isolate, RealmSwitch));
1184 realm_template->Set(
1185 String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
1186 .ToLocalChecked(),
1187 FunctionTemplate::New(isolate, RealmEval));
1188 realm_template->SetAccessor(
1189 String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
1190 .ToLocalChecked(),
1191 RealmSharedGet, RealmSharedSet);
1192 global_template->Set(
1193 String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
1194 .ToLocalChecked(),
1195 realm_template);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001196
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001197#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001198 Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
1199 performance_template->Set(
1200 String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
1201 .ToLocalChecked(),
1202 FunctionTemplate::New(isolate, PerformanceNow));
1203 global_template->Set(
1204 String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
1205 .ToLocalChecked(),
1206 performance_template);
1207
1208 Local<FunctionTemplate> worker_fun_template =
1209 FunctionTemplate::New(isolate, WorkerNew);
1210 Local<Signature> worker_signature =
1211 Signature::New(isolate, worker_fun_template);
1212 worker_fun_template->SetClassName(
1213 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1214 .ToLocalChecked());
1215 worker_fun_template->ReadOnlyPrototype();
1216 worker_fun_template->PrototypeTemplate()->Set(
1217 String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
1218 .ToLocalChecked(),
1219 FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
1220 worker_signature));
1221 worker_fun_template->PrototypeTemplate()->Set(
1222 String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
1223 .ToLocalChecked(),
1224 FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
1225 worker_signature));
1226 worker_fun_template->PrototypeTemplate()->Set(
1227 String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
1228 .ToLocalChecked(),
1229 FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
1230 worker_signature));
1231 worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
1232 global_template->Set(
1233 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1234 .ToLocalChecked(),
1235 worker_fun_template);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001236#endif // !V8_SHARED
1237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001238 Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001239 AddOSMethods(isolate, os_templ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001240 global_template->Set(
1241 String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
1242 .ToLocalChecked(),
1243 os_templ);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001244
1245 return global_template;
Steve Blocka7e24c12009-10-30 11:49:00 +00001246}
1247
Ben Murdoch097c5b22016-05-18 11:27:45 +01001248static void EmptyMessageCallback(Local<Message> message, Local<Value> error) {
1249 // Nothing to be done here, exceptions thrown up to the shell will be reported
1250 // separately by {Shell::ReportException} after they are caught.
1251}
Steve Blocka7e24c12009-10-30 11:49:00 +00001252
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001253void Shell::Initialize(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001254#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001255 // Set up counters
1256 if (i::StrLength(i::FLAG_map_counters) != 0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001257 MapCounters(isolate, i::FLAG_map_counters);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001258#endif // !V8_SHARED
Ben Murdoch097c5b22016-05-18 11:27:45 +01001259 // Disable default message reporting.
1260 isolate->AddMessageListener(EmptyMessageCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001261}
1262
1263
1264Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001265#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001266 // This needs to be a critical section since this is not thread-safe
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001267 base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001268#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001269 // Initialize the global objects
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001270 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001271 EscapableHandleScope handle_scope(isolate);
1272 Local<Context> context = Context::New(isolate, NULL, global_template);
1273 DCHECK(!context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001274 Context::Scope scope(context);
1275
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001276#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001277 i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001278 i::JSArguments js_args = i::FLAG_js_arguments;
1279 i::Handle<i::FixedArray> arguments_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001280 factory->NewFixedArray(js_args.argc);
1281 for (int j = 0; j < js_args.argc; j++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001282 i::Handle<i::String> arg =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001283 factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001284 arguments_array->set(j, *arg);
1285 }
1286 i::Handle<i::JSArray> arguments_jsarray =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001287 factory->NewJSArrayWithElements(arguments_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001288 context->Global()
1289 ->Set(context,
1290 String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
1291 .ToLocalChecked(),
1292 Utils::ToLocal(arguments_jsarray))
1293 .FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001294#endif // !V8_SHARED
1295 return handle_scope.Escape(context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001296}
1297
1298
Ben Murdoch589d6972011-11-30 16:04:58 +00001299void Shell::Exit(int exit_code) {
1300 // Use _exit instead of exit to avoid races between isolate
1301 // threads and static destructors.
1302 fflush(stdout);
1303 fflush(stderr);
1304 _exit(exit_code);
1305}
1306
1307
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001308#ifndef V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001309struct CounterAndKey {
1310 Counter* counter;
1311 const char* key;
1312};
1313
1314
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001315inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
1316 return strcmp(lhs.key, rhs.key) < 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001317}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001318#endif // !V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001319
1320
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001321void Shell::OnExit(v8::Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001322#ifndef V8_SHARED
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001323 reinterpret_cast<i::Isolate*>(isolate)->DumpAndResetCompilationStats();
Steve Blocka7e24c12009-10-30 11:49:00 +00001324 if (i::FLAG_dump_counters) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001325 int number_of_counters = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001326 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001327 number_of_counters++;
1328 }
1329 CounterAndKey* counters = new CounterAndKey[number_of_counters];
1330 int j = 0;
1331 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
1332 counters[j].counter = i.CurrentValue();
1333 counters[j].key = i.CurrentKey();
1334 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001335 std::sort(counters, counters + number_of_counters);
1336 printf("+----------------------------------------------------------------+"
1337 "-------------+\n");
1338 printf("| Name |"
1339 " Value |\n");
1340 printf("+----------------------------------------------------------------+"
1341 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001342 for (j = 0; j < number_of_counters; j++) {
1343 Counter* counter = counters[j].counter;
1344 const char* key = counters[j].key;
Steve Blocka7e24c12009-10-30 11:49:00 +00001345 if (counter->is_histogram()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001346 printf("| c:%-60s | %11i |\n", key, counter->count());
1347 printf("| t:%-60s | %11i |\n", key, counter->sample_total());
Steve Blocka7e24c12009-10-30 11:49:00 +00001348 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001349 printf("| %-62s | %11i |\n", key, counter->count());
Steve Blocka7e24c12009-10-30 11:49:00 +00001350 }
1351 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001352 printf("+----------------------------------------------------------------+"
1353 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001354 delete [] counters;
Steve Blocka7e24c12009-10-30 11:49:00 +00001355 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001356 delete counters_file_;
1357 delete counter_map_;
1358#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001359}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001360
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001361
1362
1363static FILE* FOpen(const char* path, const char* mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001364#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001365 FILE* result;
1366 if (fopen_s(&result, path, mode) == 0) {
1367 return result;
1368 } else {
1369 return NULL;
1370 }
1371#else
1372 FILE* file = fopen(path, mode);
1373 if (file == NULL) return NULL;
1374 struct stat file_stat;
1375 if (fstat(fileno(file), &file_stat) != 0) return NULL;
1376 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
1377 if (is_regular_file) return file;
1378 fclose(file);
1379 return NULL;
1380#endif
1381}
Steve Blocka7e24c12009-10-30 11:49:00 +00001382
1383
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001384static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001385 FILE* file = FOpen(name, "rb");
Steve Blocka7e24c12009-10-30 11:49:00 +00001386 if (file == NULL) return NULL;
1387
1388 fseek(file, 0, SEEK_END);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001389 size_t size = ftell(file);
Steve Blocka7e24c12009-10-30 11:49:00 +00001390 rewind(file);
1391
1392 char* chars = new char[size + 1];
1393 chars[size] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001394 for (size_t i = 0; i < size;) {
1395 i += fread(&chars[i], 1, size - i, file);
1396 if (ferror(file)) {
1397 fclose(file);
1398 delete[] chars;
1399 return nullptr;
1400 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001401 }
1402 fclose(file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001403 *size_out = static_cast<int>(size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001404 return chars;
1405}
1406
1407
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001408struct DataAndPersistent {
1409 uint8_t* data;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001410 int byte_length;
1411 Global<ArrayBuffer> handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001412};
1413
1414
1415static void ReadBufferWeakCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001416 const v8::WeakCallbackInfo<DataAndPersistent>& data) {
1417 int byte_length = data.GetParameter()->byte_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001418 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
1419 -static_cast<intptr_t>(byte_length));
1420
1421 delete[] data.GetParameter()->data;
1422 data.GetParameter()->handle.Reset();
1423 delete data.GetParameter();
1424}
1425
1426
1427void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
1428 DCHECK(sizeof(char) == sizeof(uint8_t)); // NOLINT
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001429 String::Utf8Value filename(args[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001430 int length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001431 if (*filename == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001432 Throw(args.GetIsolate(), "Error loading file");
1433 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001434 }
1435
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001436 Isolate* isolate = args.GetIsolate();
1437 DataAndPersistent* data = new DataAndPersistent;
1438 data->data = reinterpret_cast<uint8_t*>(
1439 ReadChars(args.GetIsolate(), *filename, &length));
1440 if (data->data == NULL) {
1441 delete data;
1442 Throw(args.GetIsolate(), "Error reading file");
1443 return;
1444 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001445 data->byte_length = length;
1446 Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001447 data->handle.Reset(isolate, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001448 data->handle.SetWeak(data, ReadBufferWeakCallback,
1449 v8::WeakCallbackType::kParameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001450 data->handle.MarkIndependent();
1451 isolate->AdjustAmountOfExternalAllocatedMemory(length);
1452
1453 args.GetReturnValue().Set(buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00001454}
1455
1456
Steve Blocka7e24c12009-10-30 11:49:00 +00001457// Reads a file into a v8 string.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001458Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001459 int size = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001460 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001461 if (chars == NULL) return Local<String>();
1462 Local<String> result =
1463 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1464 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 delete[] chars;
1466 return result;
1467}
1468
1469
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001470void Shell::RunShell(Isolate* isolate) {
1471 HandleScope outer_scope(isolate);
1472 v8::Local<v8::Context> context =
1473 v8::Local<v8::Context>::New(isolate, evaluation_context_);
1474 v8::Context::Scope context_scope(context);
1475 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001476 Local<String> name =
1477 String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
1478 .ToLocalChecked();
1479 printf("V8 version %s\n", V8::GetVersion());
Steve Blocka7e24c12009-10-30 11:49:00 +00001480 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001481 HandleScope inner_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001482 printf("d8> ");
1483#if defined(__native_client__)
1484 // Native Client libc is used to being embedded in Chrome and
1485 // has trouble recognizing when to flush.
1486 fflush(stdout);
1487#endif
1488 Local<String> input = Shell::ReadFromStdin(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001489 if (input.IsEmpty()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001490 ExecuteString(isolate, input, name, true, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001491 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001492 printf("\n");
1493}
1494
1495
Ben Murdoch589d6972011-11-30 16:04:58 +00001496SourceGroup::~SourceGroup() {
1497#ifndef V8_SHARED
Ben Murdoch589d6972011-11-30 16:04:58 +00001498 delete thread_;
1499 thread_ = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001500#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001501}
Steve Blocka7e24c12009-10-30 11:49:00 +00001502
Steve Blocka7e24c12009-10-30 11:49:00 +00001503
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001504void SourceGroup::Execute(Isolate* isolate) {
1505 bool exception_was_thrown = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001506 for (int i = begin_offset_; i < end_offset_; ++i) {
1507 const char* arg = argv_[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001508 Shell::SourceType source_type = Shell::SCRIPT;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001509 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1510 // Execute argument given to -e option directly.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001511 HandleScope handle_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001512 Local<String> file_name =
1513 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1514 .ToLocalChecked();
1515 Local<String> source =
1516 String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
1517 .ToLocalChecked();
1518 Shell::options.script_executed = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001519 if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1520 exception_was_thrown = true;
1521 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001522 }
1523 ++i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001524 continue;
1525 } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
1526 // Treat the next file as a module.
1527 source_type = Shell::MODULE;
1528 arg = argv_[++i];
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001529 } else if (arg[0] == '-') {
1530 // Ignore other options. They have been parsed already.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001531 continue;
1532 }
1533
1534 // Use all other arguments as names of files to load and run.
1535 HandleScope handle_scope(isolate);
1536 Local<String> file_name =
1537 String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
1538 .ToLocalChecked();
1539 Local<String> source = ReadFile(isolate, arg);
1540 if (source.IsEmpty()) {
1541 printf("Error reading '%s'\n", arg);
1542 Shell::Exit(1);
1543 }
1544 Shell::options.script_executed = true;
1545 if (!Shell::ExecuteString(isolate, source, file_name, false, true,
1546 source_type)) {
1547 exception_was_thrown = true;
1548 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001549 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001550 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001551 if (exception_was_thrown != Shell::options.expected_to_throw) {
1552 Shell::Exit(1);
1553 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001554}
Steve Blocka7e24c12009-10-30 11:49:00 +00001555
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001556
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001557Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001558 int size;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001559 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001560 if (chars == NULL) return Local<String>();
1561 Local<String> result =
1562 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1563 .ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001564 delete[] chars;
1565 return result;
1566}
1567
1568
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001569#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001570base::Thread::Options SourceGroup::GetThreadOptions() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001571 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1572 // which is not enough to parse the big literal expressions used in tests.
1573 // The stack size should be at least StackGuard::kLimitSize + some
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001574 // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001575 return base::Thread::Options("IsolateThread", 2 * MB);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001576}
1577
1578
1579void SourceGroup::ExecuteInThread() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001580 Isolate::CreateParams create_params;
1581 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1582 Isolate* isolate = Isolate::New(create_params);
1583 for (int i = 0; i < Shell::options.stress_runs; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001584 next_semaphore_.Wait();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001585 {
1586 Isolate::Scope iscope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001587 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001588 HandleScope scope(isolate);
1589 PerIsolateData data(isolate);
1590 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1591 {
1592 Context::Scope cscope(context);
1593 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1594 Execute(isolate);
1595 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001596 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001597 Shell::CollectGarbage(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001598 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001599 done_semaphore_.Signal();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001600 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001601
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001602 isolate->Dispose();
1603}
1604
1605
1606void SourceGroup::StartExecuteInThread() {
1607 if (thread_ == NULL) {
1608 thread_ = new IsolateThread(this);
1609 thread_->Start();
1610 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001611 next_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001612}
1613
1614
1615void SourceGroup::WaitForThread() {
1616 if (thread_ == NULL) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001617 done_semaphore_.Wait();
1618}
1619
1620
1621void SourceGroup::JoinThread() {
1622 if (thread_ == NULL) return;
1623 thread_->Join();
1624}
1625
1626
1627SerializationData::~SerializationData() {
1628 // Any ArrayBuffer::Contents are owned by this SerializationData object if
1629 // ownership hasn't been transferred out via ReadArrayBufferContents.
1630 // SharedArrayBuffer::Contents may be used by multiple threads, so must be
1631 // cleaned up by the main thread in Shell::CleanupWorkers().
1632 for (int i = 0; i < array_buffer_contents_.length(); ++i) {
1633 ArrayBuffer::Contents& contents = array_buffer_contents_[i];
1634 if (contents.Data()) {
1635 Shell::array_buffer_allocator->Free(contents.Data(),
1636 contents.ByteLength());
1637 }
1638 }
1639}
1640
1641
1642void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); }
1643
1644
1645void SerializationData::WriteMemory(const void* p, int length) {
1646 if (length > 0) {
1647 i::Vector<uint8_t> block = data_.AddBlock(0, length);
1648 memcpy(&block[0], p, length);
1649 }
1650}
1651
1652
1653void SerializationData::WriteArrayBufferContents(
1654 const ArrayBuffer::Contents& contents) {
1655 array_buffer_contents_.Add(contents);
1656 WriteTag(kSerializationTagTransferredArrayBuffer);
1657 int index = array_buffer_contents_.length() - 1;
1658 Write(index);
1659}
1660
1661
1662void SerializationData::WriteSharedArrayBufferContents(
1663 const SharedArrayBuffer::Contents& contents) {
1664 shared_array_buffer_contents_.Add(contents);
1665 WriteTag(kSerializationTagTransferredSharedArrayBuffer);
1666 int index = shared_array_buffer_contents_.length() - 1;
1667 Write(index);
1668}
1669
1670
1671SerializationTag SerializationData::ReadTag(int* offset) const {
1672 return static_cast<SerializationTag>(Read<uint8_t>(offset));
1673}
1674
1675
1676void SerializationData::ReadMemory(void* p, int length, int* offset) const {
1677 if (length > 0) {
1678 memcpy(p, &data_[*offset], length);
1679 (*offset) += length;
1680 }
1681}
1682
1683
1684void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents,
1685 int* offset) const {
1686 int index = Read<int>(offset);
1687 DCHECK(index < array_buffer_contents_.length());
1688 *contents = array_buffer_contents_[index];
1689 // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter
1690 // our copy so it won't be double-free'd when this SerializationData is
1691 // destroyed.
1692 array_buffer_contents_[index] = ArrayBuffer::Contents();
1693}
1694
1695
1696void SerializationData::ReadSharedArrayBufferContents(
1697 SharedArrayBuffer::Contents* contents, int* offset) const {
1698 int index = Read<int>(offset);
1699 DCHECK(index < shared_array_buffer_contents_.length());
1700 *contents = shared_array_buffer_contents_[index];
1701}
1702
1703
1704void SerializationDataQueue::Enqueue(SerializationData* data) {
1705 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1706 data_.Add(data);
1707}
1708
1709
1710bool SerializationDataQueue::Dequeue(SerializationData** data) {
1711 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1712 *data = NULL;
1713 if (data_.is_empty()) return false;
1714 *data = data_.Remove(0);
1715 return true;
1716}
1717
1718
1719bool SerializationDataQueue::IsEmpty() {
1720 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1721 return data_.is_empty();
1722}
1723
1724
1725void SerializationDataQueue::Clear() {
1726 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1727 for (int i = 0; i < data_.length(); ++i) {
1728 delete data_[i];
1729 }
1730 data_.Clear();
1731}
1732
1733
1734Worker::Worker()
1735 : in_semaphore_(0),
1736 out_semaphore_(0),
1737 thread_(NULL),
1738 script_(NULL),
1739 running_(false) {}
1740
1741
1742Worker::~Worker() {
1743 delete thread_;
1744 thread_ = NULL;
1745 delete[] script_;
1746 script_ = NULL;
1747 in_queue_.Clear();
1748 out_queue_.Clear();
1749}
1750
1751
1752void Worker::StartExecuteInThread(const char* script) {
1753 running_ = true;
1754 script_ = i::StrDup(script);
1755 thread_ = new WorkerThread(this);
1756 thread_->Start();
1757}
1758
1759
1760void Worker::PostMessage(SerializationData* data) {
1761 in_queue_.Enqueue(data);
1762 in_semaphore_.Signal();
1763}
1764
1765
1766SerializationData* Worker::GetMessage() {
1767 SerializationData* data = NULL;
1768 while (!out_queue_.Dequeue(&data)) {
1769 // If the worker is no longer running, and there are no messages in the
1770 // queue, don't expect any more messages from it.
1771 if (!base::NoBarrier_Load(&running_)) break;
1772 out_semaphore_.Wait();
1773 }
1774 return data;
1775}
1776
1777
1778void Worker::Terminate() {
1779 base::NoBarrier_Store(&running_, false);
1780 // Post NULL to wake the Worker thread message loop, and tell it to stop
1781 // running.
1782 PostMessage(NULL);
1783}
1784
1785
1786void Worker::WaitForThread() {
1787 Terminate();
1788 thread_->Join();
1789}
1790
1791
1792void Worker::ExecuteInThread() {
1793 Isolate::CreateParams create_params;
1794 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1795 Isolate* isolate = Isolate::New(create_params);
1796 {
1797 Isolate::Scope iscope(isolate);
1798 {
1799 HandleScope scope(isolate);
1800 PerIsolateData data(isolate);
1801 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1802 {
1803 Context::Scope cscope(context);
1804 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1805
1806 Local<Object> global = context->Global();
1807 Local<Value> this_value = External::New(isolate, this);
1808 Local<FunctionTemplate> postmessage_fun_template =
1809 FunctionTemplate::New(isolate, PostMessageOut, this_value);
1810
1811 Local<Function> postmessage_fun;
1812 if (postmessage_fun_template->GetFunction(context)
1813 .ToLocal(&postmessage_fun)) {
1814 global->Set(context, String::NewFromUtf8(isolate, "postMessage",
1815 NewStringType::kNormal)
1816 .ToLocalChecked(),
1817 postmessage_fun).FromJust();
1818 }
1819
1820 // First run the script
1821 Local<String> file_name =
1822 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1823 .ToLocalChecked();
1824 Local<String> source =
1825 String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
1826 .ToLocalChecked();
1827 if (Shell::ExecuteString(isolate, source, file_name, false, true)) {
1828 // Get the message handler
1829 Local<Value> onmessage =
1830 global->Get(context, String::NewFromUtf8(isolate, "onmessage",
1831 NewStringType::kNormal)
1832 .ToLocalChecked()).ToLocalChecked();
1833 if (onmessage->IsFunction()) {
1834 Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
1835 // Now wait for messages
1836 while (true) {
1837 in_semaphore_.Wait();
1838 SerializationData* data;
1839 if (!in_queue_.Dequeue(&data)) continue;
1840 if (data == NULL) {
1841 break;
1842 }
1843 int offset = 0;
1844 Local<Value> data_value;
1845 if (Shell::DeserializeValue(isolate, *data, &offset)
1846 .ToLocal(&data_value)) {
1847 Local<Value> argv[] = {data_value};
1848 (void)onmessage_fun->Call(context, global, 1, argv);
1849 }
1850 delete data;
1851 }
1852 }
1853 }
1854 }
1855 }
1856 Shell::CollectGarbage(isolate);
1857 }
1858 isolate->Dispose();
1859
1860 // Post NULL to wake the thread waiting on GetMessage() if there is one.
1861 out_queue_.Enqueue(NULL);
1862 out_semaphore_.Signal();
1863}
1864
1865
1866void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
1867 Isolate* isolate = args.GetIsolate();
1868 HandleScope handle_scope(isolate);
1869
1870 if (args.Length() < 1) {
1871 Throw(isolate, "Invalid argument");
1872 return;
1873 }
1874
1875 Local<Value> message = args[0];
1876
1877 // TODO(binji): Allow transferring from worker to main thread?
1878 Shell::ObjectList to_transfer;
1879
1880 Shell::ObjectList seen_objects;
1881 SerializationData* data = new SerializationData;
1882 if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects,
1883 data)) {
1884 DCHECK(args.Data()->IsExternal());
1885 Local<External> this_value = Local<External>::Cast(args.Data());
1886 Worker* worker = static_cast<Worker*>(this_value->Value());
1887 worker->out_queue_.Enqueue(data);
1888 worker->out_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001889 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001890 delete data;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001891 }
1892}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001893#endif // !V8_SHARED
1894
1895
1896void SetFlagsFromString(const char* flags) {
1897 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
1898}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001899
1900
1901bool Shell::SetOptions(int argc, char* argv[]) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001902 bool logfile_per_isolate = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001903 for (int i = 0; i < argc; i++) {
1904 if (strcmp(argv[i], "--stress-opt") == 0) {
1905 options.stress_opt = true;
1906 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001907 } else if (strcmp(argv[i], "--nostress-opt") == 0) {
1908 options.stress_opt = false;
1909 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001910 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1911 options.stress_deopt = true;
1912 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001913 } else if (strcmp(argv[i], "--mock-arraybuffer-allocator") == 0) {
1914 options.mock_arraybuffer_allocator = true;
1915 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001916 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1917 // No support for stressing if we can't use --always-opt.
1918 options.stress_opt = false;
1919 options.stress_deopt = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001920 } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
1921 logfile_per_isolate = true;
1922 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001923 } else if (strcmp(argv[i], "--shell") == 0) {
1924 options.interactive_shell = true;
1925 argv[i] = NULL;
1926 } else if (strcmp(argv[i], "--test") == 0) {
1927 options.test_shell = true;
1928 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001929 } else if (strcmp(argv[i], "--notest") == 0 ||
1930 strcmp(argv[i], "--no-test") == 0) {
1931 options.test_shell = false;
1932 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001933 } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
1934 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001935 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001936 } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
1937 options.invoke_weak_callbacks = true;
1938 // TODO(jochen) See issue 3351
1939 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001940 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001941 } else if (strcmp(argv[i], "--omit-quit") == 0) {
1942 options.omit_quit = true;
1943 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001944 } else if (strcmp(argv[i], "-f") == 0) {
1945 // Ignore any -f flags for compatibility with other stand-alone
1946 // JavaScript engines.
1947 continue;
1948 } else if (strcmp(argv[i], "--isolate") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001949#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001950 printf("D8 with shared library does not support multi-threading\n");
1951 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001952#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001953 options.num_isolates++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001954 } else if (strcmp(argv[i], "--dump-heap-constants") == 0) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001955#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001956 printf("D8 with shared library does not support constant dumping\n");
Ben Murdoch589d6972011-11-30 16:04:58 +00001957 return false;
1958#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001959 options.dump_heap_constants = true;
1960 argv[i] = NULL;
Ben Murdoch589d6972011-11-30 16:04:58 +00001961#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001962 } else if (strcmp(argv[i], "--throws") == 0) {
1963 options.expected_to_throw = true;
1964 argv[i] = NULL;
1965 } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
1966 options.icu_data_file = argv[i] + 16;
1967 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001968#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001969 } else if (strcmp(argv[i], "--dump-counters") == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001970 printf("D8 with shared library does not include counters\n");
1971 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001972#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001973#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1974 } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
1975 options.natives_blob = argv[i] + 15;
1976 argv[i] = NULL;
1977 } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
1978 options.snapshot_blob = argv[i] + 16;
1979 argv[i] = NULL;
1980#endif // V8_USE_EXTERNAL_STARTUP_DATA
1981 } else if (strcmp(argv[i], "--cache") == 0 ||
1982 strncmp(argv[i], "--cache=", 8) == 0) {
1983 const char* value = argv[i] + 7;
1984 if (!*value || strncmp(value, "=code", 6) == 0) {
1985 options.compile_options = v8::ScriptCompiler::kProduceCodeCache;
1986 } else if (strncmp(value, "=parse", 7) == 0) {
1987 options.compile_options = v8::ScriptCompiler::kProduceParserCache;
1988 } else if (strncmp(value, "=none", 6) == 0) {
1989 options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
1990 } else {
1991 printf("Unknown option to --cache.\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001992 return false;
1993 }
1994 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001995 }
1996 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001997
1998 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1999
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002000 bool enable_harmony_modules = false;
2001
Ben Murdoch589d6972011-11-30 16:04:58 +00002002 // Set up isolated source groups.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002003 options.isolate_sources = new SourceGroup[options.num_isolates];
2004 SourceGroup* current = options.isolate_sources;
2005 current->Begin(argv, 1);
2006 for (int i = 1; i < argc; i++) {
2007 const char* str = argv[i];
2008 if (strcmp(str, "--isolate") == 0) {
2009 current->End(i);
2010 current++;
2011 current->Begin(argv, i + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002012 } else if (strcmp(str, "--module") == 0) {
2013 // Pass on to SourceGroup, which understands this option.
2014 enable_harmony_modules = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002015 } else if (strncmp(argv[i], "--", 2) == 0) {
2016 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002017 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
2018 options.script_executed = true;
2019 } else if (strncmp(str, "-", 1) != 0) {
2020 // Not a flag, so it must be a script to execute.
2021 options.script_executed = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002022 }
2023 }
2024 current->End(argc);
2025
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002026 if (!logfile_per_isolate && options.num_isolates) {
2027 SetFlagsFromString("--nologfile_per_isolate");
2028 }
2029
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002030 if (enable_harmony_modules) {
2031 SetFlagsFromString("--harmony-modules");
2032 }
2033
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002034 return true;
2035}
2036
2037
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002038int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002039#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002040 for (int i = 1; i < options.num_isolates; ++i) {
2041 options.isolate_sources[i].StartExecuteInThread();
2042 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002043#endif // !V8_SHARED
2044 {
2045 HandleScope scope(isolate);
2046 Local<Context> context = CreateEvaluationContext(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002047 if (last_run && options.use_interactive_shell()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002048 // Keep using the same context in the interactive shell.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002049 evaluation_context_.Reset(isolate, context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002050 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002051 {
2052 Context::Scope cscope(context);
2053 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2054 options.isolate_sources[0].Execute(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002055 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002056 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002057 CollectGarbage(isolate);
2058#ifndef V8_SHARED
2059 for (int i = 1; i < options.num_isolates; ++i) {
2060 if (last_run) {
2061 options.isolate_sources[i].JoinThread();
2062 } else {
2063 options.isolate_sources[i].WaitForThread();
2064 }
2065 }
2066 CleanupWorkers();
2067#endif // !V8_SHARED
2068 return 0;
2069}
2070
2071
2072void Shell::CollectGarbage(Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002073 if (options.send_idle_notification) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002074 const double kLongIdlePauseInSeconds = 1.0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002075 isolate->ContextDisposedNotification();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002076 isolate->IdleNotificationDeadline(
2077 g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002078 }
2079 if (options.invoke_weak_callbacks) {
2080 // By sending a low memory notifications, we will try hard to collect all
2081 // garbage and will therefore also invoke all weak callbacks of actually
2082 // unreachable persistent handles.
2083 isolate->LowMemoryNotification();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002084 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002085}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002086
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002087
2088void Shell::EmptyMessageQueues(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002089#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002090 if (!i::FLAG_verify_predictable) {
2091#endif
2092 while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue;
2093#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002094 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002095#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00002096}
2097
2098
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002099#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002100bool Shell::SerializeValue(Isolate* isolate, Local<Value> value,
2101 const ObjectList& to_transfer,
2102 ObjectList* seen_objects,
2103 SerializationData* out_data) {
2104 DCHECK(out_data);
2105 Local<Context> context = isolate->GetCurrentContext();
2106
2107 if (value->IsUndefined()) {
2108 out_data->WriteTag(kSerializationTagUndefined);
2109 } else if (value->IsNull()) {
2110 out_data->WriteTag(kSerializationTagNull);
2111 } else if (value->IsTrue()) {
2112 out_data->WriteTag(kSerializationTagTrue);
2113 } else if (value->IsFalse()) {
2114 out_data->WriteTag(kSerializationTagFalse);
2115 } else if (value->IsNumber()) {
2116 Local<Number> num = Local<Number>::Cast(value);
2117 double value = num->Value();
2118 out_data->WriteTag(kSerializationTagNumber);
2119 out_data->Write(value);
2120 } else if (value->IsString()) {
2121 v8::String::Utf8Value str(value);
2122 out_data->WriteTag(kSerializationTagString);
2123 out_data->Write(str.length());
2124 out_data->WriteMemory(*str, str.length());
2125 } else if (value->IsArray()) {
2126 Local<Array> array = Local<Array>::Cast(value);
2127 if (FindInObjectList(array, *seen_objects)) {
2128 Throw(isolate, "Duplicated arrays not supported");
2129 return false;
2130 }
2131 seen_objects->Add(array);
2132 out_data->WriteTag(kSerializationTagArray);
2133 uint32_t length = array->Length();
2134 out_data->Write(length);
2135 for (uint32_t i = 0; i < length; ++i) {
2136 Local<Value> element_value;
2137 if (array->Get(context, i).ToLocal(&element_value)) {
2138 if (!SerializeValue(isolate, element_value, to_transfer, seen_objects,
2139 out_data))
2140 return false;
2141 } else {
2142 Throw(isolate, "Failed to serialize array element.");
2143 return false;
2144 }
2145 }
2146 } else if (value->IsArrayBuffer()) {
2147 Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value);
2148 if (FindInObjectList(array_buffer, *seen_objects)) {
2149 Throw(isolate, "Duplicated array buffers not supported");
2150 return false;
2151 }
2152 seen_objects->Add(array_buffer);
2153 if (FindInObjectList(array_buffer, to_transfer)) {
2154 // Transfer ArrayBuffer
2155 if (!array_buffer->IsNeuterable()) {
2156 Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer");
2157 return false;
2158 }
2159
2160 ArrayBuffer::Contents contents = array_buffer->IsExternal()
2161 ? array_buffer->GetContents()
2162 : array_buffer->Externalize();
2163 array_buffer->Neuter();
2164 out_data->WriteArrayBufferContents(contents);
2165 } else {
2166 ArrayBuffer::Contents contents = array_buffer->GetContents();
2167 // Clone ArrayBuffer
2168 if (contents.ByteLength() > i::kMaxInt) {
2169 Throw(isolate, "ArrayBuffer is too big to clone");
2170 return false;
2171 }
2172
2173 int32_t byte_length = static_cast<int32_t>(contents.ByteLength());
2174 out_data->WriteTag(kSerializationTagArrayBuffer);
2175 out_data->Write(byte_length);
2176 out_data->WriteMemory(contents.Data(), byte_length);
2177 }
2178 } else if (value->IsSharedArrayBuffer()) {
2179 Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value);
2180 if (FindInObjectList(sab, *seen_objects)) {
2181 Throw(isolate, "Duplicated shared array buffers not supported");
2182 return false;
2183 }
2184 seen_objects->Add(sab);
2185 if (!FindInObjectList(sab, to_transfer)) {
2186 Throw(isolate, "SharedArrayBuffer must be transferred");
2187 return false;
2188 }
2189
2190 SharedArrayBuffer::Contents contents;
2191 if (sab->IsExternal()) {
2192 contents = sab->GetContents();
2193 } else {
2194 contents = sab->Externalize();
2195 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2196 externalized_shared_contents_.Add(contents);
2197 }
2198 out_data->WriteSharedArrayBufferContents(contents);
2199 } else if (value->IsObject()) {
2200 Local<Object> object = Local<Object>::Cast(value);
2201 if (FindInObjectList(object, *seen_objects)) {
2202 Throw(isolate, "Duplicated objects not supported");
2203 return false;
2204 }
2205 seen_objects->Add(object);
2206 Local<Array> property_names;
2207 if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
2208 Throw(isolate, "Unable to get property names");
2209 return false;
2210 }
2211
2212 uint32_t length = property_names->Length();
2213 out_data->WriteTag(kSerializationTagObject);
2214 out_data->Write(length);
2215 for (uint32_t i = 0; i < length; ++i) {
2216 Local<Value> name;
2217 Local<Value> property_value;
2218 if (property_names->Get(context, i).ToLocal(&name) &&
2219 object->Get(context, name).ToLocal(&property_value)) {
2220 if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data))
2221 return false;
2222 if (!SerializeValue(isolate, property_value, to_transfer, seen_objects,
2223 out_data))
2224 return false;
2225 } else {
2226 Throw(isolate, "Failed to serialize property.");
2227 return false;
2228 }
2229 }
2230 } else {
2231 Throw(isolate, "Don't know how to serialize object");
2232 return false;
2233 }
2234
2235 return true;
2236}
2237
2238
2239MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
2240 const SerializationData& data,
2241 int* offset) {
2242 DCHECK(offset);
2243 EscapableHandleScope scope(isolate);
2244 // This function should not use utility_context_ because it is running on a
2245 // different thread.
2246 Local<Value> result;
2247 SerializationTag tag = data.ReadTag(offset);
2248
2249 switch (tag) {
2250 case kSerializationTagUndefined:
2251 result = Undefined(isolate);
2252 break;
2253 case kSerializationTagNull:
2254 result = Null(isolate);
2255 break;
2256 case kSerializationTagTrue:
2257 result = True(isolate);
2258 break;
2259 case kSerializationTagFalse:
2260 result = False(isolate);
2261 break;
2262 case kSerializationTagNumber:
2263 result = Number::New(isolate, data.Read<double>(offset));
2264 break;
2265 case kSerializationTagString: {
2266 int length = data.Read<int>(offset);
2267 CHECK(length >= 0);
2268 std::vector<char> buffer(length + 1); // + 1 so it is never empty.
2269 data.ReadMemory(&buffer[0], length, offset);
2270 MaybeLocal<String> str =
2271 String::NewFromUtf8(isolate, &buffer[0], NewStringType::kNormal,
2272 length).ToLocalChecked();
2273 if (!str.IsEmpty()) result = str.ToLocalChecked();
2274 break;
2275 }
2276 case kSerializationTagArray: {
2277 uint32_t length = data.Read<uint32_t>(offset);
2278 Local<Array> array = Array::New(isolate, length);
2279 for (uint32_t i = 0; i < length; ++i) {
2280 Local<Value> element_value;
2281 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value));
2282 array->Set(isolate->GetCurrentContext(), i, element_value).FromJust();
2283 }
2284 result = array;
2285 break;
2286 }
2287 case kSerializationTagObject: {
2288 int length = data.Read<int>(offset);
2289 Local<Object> object = Object::New(isolate);
2290 for (int i = 0; i < length; ++i) {
2291 Local<Value> property_name;
2292 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name));
2293 Local<Value> property_value;
2294 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value));
2295 object->Set(isolate->GetCurrentContext(), property_name, property_value)
2296 .FromJust();
2297 }
2298 result = object;
2299 break;
2300 }
2301 case kSerializationTagArrayBuffer: {
2302 int32_t byte_length = data.Read<int32_t>(offset);
2303 Local<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length);
2304 ArrayBuffer::Contents contents = array_buffer->GetContents();
2305 DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength());
2306 data.ReadMemory(contents.Data(), byte_length, offset);
2307 result = array_buffer;
2308 break;
2309 }
2310 case kSerializationTagTransferredArrayBuffer: {
2311 ArrayBuffer::Contents contents;
2312 data.ReadArrayBufferContents(&contents, offset);
2313 result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(),
2314 ArrayBufferCreationMode::kInternalized);
2315 break;
2316 }
2317 case kSerializationTagTransferredSharedArrayBuffer: {
2318 SharedArrayBuffer::Contents contents;
2319 data.ReadSharedArrayBufferContents(&contents, offset);
2320 result = SharedArrayBuffer::New(isolate, contents.Data(),
2321 contents.ByteLength());
2322 break;
2323 }
2324 default:
2325 UNREACHABLE();
2326 }
2327
2328 return scope.Escape(result);
2329}
2330
2331
2332void Shell::CleanupWorkers() {
2333 // Make a copy of workers_, because we don't want to call Worker::Terminate
2334 // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
2335 // create a new Worker, it would deadlock.
2336 i::List<Worker*> workers_copy;
2337 {
2338 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2339 allow_new_workers_ = false;
2340 workers_copy.AddAll(workers_);
2341 workers_.Clear();
2342 }
2343
2344 for (int i = 0; i < workers_copy.length(); ++i) {
2345 Worker* worker = workers_copy[i];
2346 worker->WaitForThread();
2347 delete worker;
2348 }
2349
2350 // Now that all workers are terminated, we can re-enable Worker creation.
2351 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2352 allow_new_workers_ = true;
2353
2354 for (int i = 0; i < externalized_shared_contents_.length(); ++i) {
2355 const SharedArrayBuffer::Contents& contents =
2356 externalized_shared_contents_[i];
2357 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
2358 }
2359 externalized_shared_contents_.Clear();
2360}
2361
2362
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002363static void DumpHeapConstants(i::Isolate* isolate) {
2364 i::Heap* heap = isolate->heap();
2365
2366 // Dump the INSTANCE_TYPES table to the console.
2367 printf("# List of known V8 instance types.\n");
2368#define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T);
2369 printf("INSTANCE_TYPES = {\n");
2370 INSTANCE_TYPE_LIST(DUMP_TYPE)
2371 printf("}\n");
2372#undef DUMP_TYPE
2373
2374 // Dump the KNOWN_MAP table to the console.
2375 printf("\n# List of known V8 maps.\n");
2376#define ROOT_LIST_CASE(type, name, camel_name) \
2377 if (n == NULL && o == heap->name()) n = #camel_name;
2378#define STRUCT_LIST_CASE(upper_name, camel_name, name) \
2379 if (n == NULL && o == heap->name##_map()) n = #camel_name "Map";
2380 i::HeapObjectIterator it(heap->map_space());
2381 printf("KNOWN_MAPS = {\n");
2382 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2383 i::Map* m = i::Map::cast(o);
2384 const char* n = NULL;
2385 intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
2386 int t = m->instance_type();
2387 ROOT_LIST(ROOT_LIST_CASE)
2388 STRUCT_LIST(STRUCT_LIST_CASE)
2389 if (n == NULL) continue;
2390 printf(" 0x%05" V8PRIxPTR ": (%d, \"%s\"),\n", p, t, n);
2391 }
2392 printf("}\n");
2393#undef STRUCT_LIST_CASE
2394#undef ROOT_LIST_CASE
2395
2396 // Dump the KNOWN_OBJECTS table to the console.
2397 printf("\n# List of known V8 objects.\n");
2398#define ROOT_LIST_CASE(type, name, camel_name) \
2399 if (n == NULL && o == heap->name()) n = #camel_name;
2400 i::OldSpaces spit(heap);
2401 printf("KNOWN_OBJECTS = {\n");
2402 for (i::PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
2403 i::HeapObjectIterator it(s);
2404 const char* sname = AllocationSpaceName(s->identity());
2405 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2406 const char* n = NULL;
2407 intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
2408 ROOT_LIST(ROOT_LIST_CASE)
2409 if (n == NULL) continue;
2410 printf(" (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", sname, p, n);
2411 }
2412 }
2413 printf("}\n");
2414#undef ROOT_LIST_CASE
2415}
2416#endif // !V8_SHARED
2417
2418
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002419int Shell::Main(int argc, char* argv[]) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002420#if (defined(_WIN32) || defined(_WIN64))
2421 UINT new_flags =
2422 SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
2423 UINT existing_flags = SetErrorMode(new_flags);
2424 SetErrorMode(existing_flags | new_flags);
2425#if defined(_MSC_VER)
2426 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2427 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
2428 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2429 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
2430 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2431 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
2432 _set_error_mode(_OUT_TO_STDERR);
2433#endif // defined(_MSC_VER)
2434#endif // defined(_WIN32) || defined(_WIN64)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002435 if (!SetOptions(argc, argv)) return 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002436 v8::V8::InitializeICU(options.icu_data_file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002437#ifndef V8_SHARED
2438 g_platform = i::FLAG_verify_predictable
2439 ? new PredictablePlatform()
2440 : v8::platform::CreateDefaultPlatform();
2441#else
2442 g_platform = v8::platform::CreateDefaultPlatform();
2443#endif // !V8_SHARED
2444
2445 v8::V8::InitializePlatform(g_platform);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002446 v8::V8::Initialize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002447 if (options.natives_blob || options.snapshot_blob) {
2448 v8::V8::InitializeExternalStartupData(options.natives_blob,
2449 options.snapshot_blob);
2450 } else {
2451 v8::V8::InitializeExternalStartupData(argv[0]);
2452 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002453 SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002454 SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002455 SetFlagsFromString("--redirect-code-traces-to=code.asm");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002456 int result = 0;
2457 Isolate::CreateParams create_params;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002458 ShellArrayBufferAllocator shell_array_buffer_allocator;
2459 MockArrayBufferAllocator mock_arraybuffer_allocator;
2460 if (options.mock_arraybuffer_allocator) {
2461 Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
2462 } else {
2463 Shell::array_buffer_allocator = &shell_array_buffer_allocator;
2464 }
2465 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002466#ifdef ENABLE_VTUNE_JIT_INTERFACE
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002467 create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002468#endif
2469#ifndef V8_SHARED
2470 create_params.constraints.ConfigureDefaults(
2471 base::SysInfo::AmountOfPhysicalMemory(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002472 base::SysInfo::AmountOfVirtualMemory());
2473
2474 Shell::counter_map_ = new CounterMap();
2475 if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
2476 create_params.counter_lookup_callback = LookupCounter;
2477 create_params.create_histogram_callback = CreateHistogram;
2478 create_params.add_histogram_sample_callback = AddHistogramSample;
2479 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002480#endif
2481 Isolate* isolate = Isolate::New(create_params);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002482 {
2483 Isolate::Scope scope(isolate);
2484 Initialize(isolate);
2485 PerIsolateData data(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002486
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002487#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002488 if (options.dump_heap_constants) {
2489 DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate));
2490 return 0;
2491 }
2492#endif
2493
2494 if (options.stress_opt || options.stress_deopt) {
2495 Testing::SetStressRunType(options.stress_opt
2496 ? Testing::kStressTypeOpt
2497 : Testing::kStressTypeDeopt);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002498 options.stress_runs = Testing::GetStressRuns();
2499 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2500 printf("============ Stress %d/%d ============\n", i + 1,
2501 options.stress_runs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002502 Testing::PrepareStressRun(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002503 bool last_run = i == options.stress_runs - 1;
2504 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002505 }
2506 printf("======== Full Deoptimization =======\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002507 Testing::DeoptimizeAll(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002508#if !defined(V8_SHARED)
2509 } else if (i::FLAG_stress_runs > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002510 options.stress_runs = i::FLAG_stress_runs;
2511 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2512 printf("============ Run %d/%d ============\n", i + 1,
2513 options.stress_runs);
2514 bool last_run = i == options.stress_runs - 1;
2515 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002516 }
2517#endif
2518 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002519 bool last_run = true;
2520 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002521 }
2522
2523 // Run interactive shell if explicitly requested or if no script has been
2524 // executed, but never on --test
2525 if (options.use_interactive_shell()) {
2526#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002527 InstallUtilityScript(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002528#endif // !V8_SHARED
2529 RunShell(isolate);
2530 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002531
2532 // Shut down contexts and collect garbage.
2533 evaluation_context_.Reset();
2534#ifndef V8_SHARED
2535 utility_context_.Reset();
2536#endif // !V8_SHARED
2537 CollectGarbage(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002538 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002539 OnExit(isolate);
2540#ifndef V8_SHARED
2541 // Dump basic block profiling data.
2542 if (i::BasicBlockProfiler* profiler =
2543 reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
2544 i::OFStream os(stdout);
2545 os << *profiler;
2546 }
2547#endif // !V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002548 isolate->Dispose();
2549 V8::Dispose();
2550 V8::ShutdownPlatform();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002551 delete g_platform;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002552
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002553 return result;
2554}
2555
Steve Blocka7e24c12009-10-30 11:49:00 +00002556} // namespace v8
2557
2558
Ben Murdoch257744e2011-11-30 15:57:28 +00002559#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +00002560int main(int argc, char* argv[]) {
2561 return v8::Shell::Main(argc, argv);
2562}
Ben Murdoch257744e2011-11-30 15:57:28 +00002563#endif