blob: 06883803f90091503fd133499ef3608f048ae8aa [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,
Ben Murdochda12d292016-06-02 14:46:10 +0100136 const char* name, const char* scope, uint64_t id,
137 uint64_t bind_id, int numArgs, const char** argNames,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000138 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 Murdochda12d292016-06-02 14:46:10 +0100254Global<Function> Shell::stringify_function_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000255base::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 {
Ben Murdochda12d292016-06-02 14:46:10 +0100415 v8::String::Utf8Value str(Stringify(isolate, result));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000416 fwrite(*str, sizeof(**str), str.length(), stdout);
417 printf("\n");
418 }
419#endif
420 }
421 return true;
Steve Blocka7e24c12009-10-30 11:49:00 +0000422}
423
424
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000425PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
426 data_->realm_count_ = 1;
427 data_->realm_current_ = 0;
428 data_->realm_switch_ = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429 data_->realms_ = new Global<Context>[1];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000430 data_->realms_[0].Reset(data_->isolate_,
431 data_->isolate_->GetEnteredContext());
Steve Blocka7e24c12009-10-30 11:49:00 +0000432}
433
434
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000435PerIsolateData::RealmScope::~RealmScope() {
436 // Drop realms to avoid keeping them alive.
437 for (int i = 0; i < data_->realm_count_; ++i)
438 data_->realms_[i].Reset();
439 delete[] data_->realms_;
440 if (!data_->realm_shared_.IsEmpty())
441 data_->realm_shared_.Reset();
442}
443
444
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000445int PerIsolateData::RealmFind(Local<Context> context) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000446 for (int i = 0; i < realm_count_; ++i) {
447 if (realms_[i] == context) return i;
448 }
449 return -1;
450}
451
452
453int PerIsolateData::RealmIndexOrThrow(
454 const v8::FunctionCallbackInfo<v8::Value>& args,
455 int arg_offset) {
456 if (args.Length() < arg_offset || !args[arg_offset]->IsNumber()) {
457 Throw(args.GetIsolate(), "Invalid argument");
458 return -1;
459 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460 int index = args[arg_offset]
461 ->Int32Value(args.GetIsolate()->GetCurrentContext())
462 .FromMaybe(-1);
463 if (index < 0 || index >= realm_count_ || realms_[index].IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000464 Throw(args.GetIsolate(), "Invalid realm index");
465 return -1;
466 }
467 return index;
468}
469
470
471#ifndef V8_SHARED
472// performance.now() returns a time stamp as double, measured in milliseconds.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473// When FLAG_verify_predictable mode is enabled it returns result of
474// v8::Platform::MonotonicallyIncreasingTime().
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000475void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
476 if (i::FLAG_verify_predictable) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000477 args.GetReturnValue().Set(g_platform->MonotonicallyIncreasingTime());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000478 } else {
479 base::TimeDelta delta =
480 base::TimeTicks::HighResolutionNow() - kInitialTicks;
481 args.GetReturnValue().Set(delta.InMillisecondsF());
482 }
483}
484#endif // !V8_SHARED
485
486
487// Realm.current() returns the index of the currently active realm.
488void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
489 Isolate* isolate = args.GetIsolate();
490 PerIsolateData* data = PerIsolateData::Get(isolate);
491 int index = data->RealmFind(isolate->GetEnteredContext());
492 if (index == -1) return;
493 args.GetReturnValue().Set(index);
494}
495
496
497// Realm.owner(o) returns the index of the realm that created o.
498void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
499 Isolate* isolate = args.GetIsolate();
500 PerIsolateData* data = PerIsolateData::Get(isolate);
501 if (args.Length() < 1 || !args[0]->IsObject()) {
502 Throw(args.GetIsolate(), "Invalid argument");
503 return;
504 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000505 int index = data->RealmFind(args[0]
506 ->ToObject(isolate->GetCurrentContext())
507 .ToLocalChecked()
508 ->CreationContext());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000509 if (index == -1) return;
510 args.GetReturnValue().Set(index);
511}
512
513
514// Realm.global(i) returns the global object of realm i.
515// (Note that properties of global objects cannot be read/written cross-realm.)
516void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
517 PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
518 int index = data->RealmIndexOrThrow(args, 0);
519 if (index == -1) return;
520 args.GetReturnValue().Set(
521 Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
522}
523
524
525// Realm.create() creates a new realm and returns its index.
526void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
527 Isolate* isolate = args.GetIsolate();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000528 TryCatch try_catch(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000529 PerIsolateData* data = PerIsolateData::Get(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000530 Global<Context>* old_realms = data->realms_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000531 int index = data->realm_count_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000532 data->realms_ = new Global<Context>[++data->realm_count_];
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000533 for (int i = 0; i < index; ++i) {
534 data->realms_[i].Reset(isolate, old_realms[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000535 old_realms[i].Reset();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000536 }
537 delete[] old_realms;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000538 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
539 Local<Context> context = Context::New(isolate, NULL, global_template);
540 if (context.IsEmpty()) {
541 DCHECK(try_catch.HasCaught());
542 try_catch.ReThrow();
543 return;
544 }
545 data->realms_[index].Reset(isolate, context);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000546 args.GetReturnValue().Set(index);
547}
548
549
550// Realm.dispose(i) disposes the reference to the realm i.
551void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
552 Isolate* isolate = args.GetIsolate();
553 PerIsolateData* data = PerIsolateData::Get(isolate);
554 int index = data->RealmIndexOrThrow(args, 0);
555 if (index == -1) return;
556 if (index == 0 ||
557 index == data->realm_current_ || index == data->realm_switch_) {
558 Throw(args.GetIsolate(), "Invalid realm index");
559 return;
560 }
561 data->realms_[index].Reset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000562 isolate->ContextDisposedNotification();
563 isolate->IdleNotificationDeadline(g_platform->MonotonicallyIncreasingTime());
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000564}
565
566
567// Realm.switch(i) switches to the realm i for consecutive interactive inputs.
568void Shell::RealmSwitch(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 data->realm_switch_ = index;
574}
575
576
577// Realm.eval(i, s) evaluates s in realm i and returns the result.
578void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
579 Isolate* isolate = args.GetIsolate();
580 PerIsolateData* data = PerIsolateData::Get(isolate);
581 int index = data->RealmIndexOrThrow(args, 0);
582 if (index == -1) return;
583 if (args.Length() < 2 || !args[1]->IsString()) {
584 Throw(args.GetIsolate(), "Invalid argument");
585 return;
586 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000587 ScriptCompiler::Source script_source(
588 args[1]->ToString(isolate->GetCurrentContext()).ToLocalChecked());
589 Local<UnboundScript> script;
590 if (!ScriptCompiler::CompileUnboundScript(isolate, &script_source)
591 .ToLocal(&script)) {
592 return;
593 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000594 Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
595 realm->Enter();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000596 Local<Value> result;
597 if (!script->BindToCurrentContext()->Run(realm).ToLocal(&result)) {
598 realm->Exit();
599 return;
600 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000601 realm->Exit();
602 args.GetReturnValue().Set(result);
603}
604
605
606// Realm.shared is an accessor for a single shared value across realms.
607void Shell::RealmSharedGet(Local<String> property,
608 const PropertyCallbackInfo<Value>& info) {
609 Isolate* isolate = info.GetIsolate();
610 PerIsolateData* data = PerIsolateData::Get(isolate);
611 if (data->realm_shared_.IsEmpty()) return;
612 info.GetReturnValue().Set(data->realm_shared_);
613}
614
615void Shell::RealmSharedSet(Local<String> property,
616 Local<Value> value,
617 const PropertyCallbackInfo<void>& info) {
618 Isolate* isolate = info.GetIsolate();
619 PerIsolateData* data = PerIsolateData::Get(isolate);
620 data->realm_shared_.Reset(isolate, value);
621}
622
623
624void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
625 Write(args);
626 printf("\n");
627 fflush(stdout);
628}
629
630
631void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000632 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000633 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000634 if (i != 0) {
635 printf(" ");
636 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000637
638 // Explicitly catch potential exceptions in toString().
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000639 v8::TryCatch try_catch(args.GetIsolate());
640 Local<Value> arg = args[i];
641 Local<String> str_obj;
642
643 if (arg->IsSymbol()) {
644 arg = Local<Symbol>::Cast(arg)->Name();
645 }
646 if (!arg->ToString(args.GetIsolate()->GetCurrentContext())
647 .ToLocal(&str_obj)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000648 try_catch.ReThrow();
649 return;
650 }
651
652 v8::String::Utf8Value str(str_obj);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000653 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
Steve Blockd0582a62009-12-15 09:54:21 +0000654 if (n != str.length()) {
655 printf("Error in fwrite\n");
Ben Murdoch589d6972011-11-30 16:04:58 +0000656 Exit(1);
Steve Blockd0582a62009-12-15 09:54:21 +0000657 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000658 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000659}
660
661
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000662void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000663 String::Utf8Value file(args[0]);
664 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000665 Throw(args.GetIsolate(), "Error loading file");
666 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000667 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000668 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000669 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000670 Throw(args.GetIsolate(), "Error loading file");
671 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000672 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000673 args.GetReturnValue().Set(source);
Steve Blocka7e24c12009-10-30 11:49:00 +0000674}
675
676
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000677Local<String> Shell::ReadFromStdin(Isolate* isolate) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000678 static const int kBufferSize = 256;
679 char buffer[kBufferSize];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000680 Local<String> accumulator =
681 String::NewFromUtf8(isolate, "", NewStringType::kNormal).ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000682 int length;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000683 while (true) {
684 // Continue reading if the line ends with an escape '\\' or the line has
685 // not been fully read into the buffer yet (does not end with '\n').
686 // If fgets gets an error, just give up.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100687 char* input = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000688 input = fgets(buffer, kBufferSize, stdin);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000689 if (input == NULL) return Local<String>();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000690 length = static_cast<int>(strlen(buffer));
691 if (length == 0) {
692 return accumulator;
693 } else if (buffer[length-1] != '\n') {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000694 accumulator = String::Concat(
695 accumulator,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000696 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal, length)
697 .ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000698 } else if (length > 1 && buffer[length-2] == '\\') {
699 buffer[length-2] = '\n';
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000700 accumulator = String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000701 accumulator,
702 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
703 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000704 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000705 return String::Concat(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000706 accumulator,
707 String::NewFromUtf8(isolate, buffer, NewStringType::kNormal,
708 length - 1).ToLocalChecked());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000709 }
710 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000711}
712
713
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000714void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000715 for (int i = 0; i < args.Length(); i++) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000716 HandleScope handle_scope(args.GetIsolate());
Steve Blocka7e24c12009-10-30 11:49:00 +0000717 String::Utf8Value file(args[i]);
718 if (*file == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000719 Throw(args.GetIsolate(), "Error loading file");
720 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000721 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000722 Local<String> source = ReadFile(args.GetIsolate(), *file);
Steve Blocka7e24c12009-10-30 11:49:00 +0000723 if (source.IsEmpty()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000724 Throw(args.GetIsolate(), "Error loading file");
725 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000726 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000727 if (!ExecuteString(
728 args.GetIsolate(), source,
729 String::NewFromUtf8(args.GetIsolate(), *file,
730 NewStringType::kNormal).ToLocalChecked(),
731 false, true)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000732 Throw(args.GetIsolate(), "Error executing file");
733 return;
Steve Blocka7e24c12009-10-30 11:49:00 +0000734 }
735 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100736}
737
738
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000739#ifndef V8_SHARED
740void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
741 Isolate* isolate = args.GetIsolate();
742 HandleScope handle_scope(isolate);
743 if (args.Length() < 1 || !args[0]->IsString()) {
744 Throw(args.GetIsolate(), "1st argument must be string");
745 return;
746 }
747
748 if (!args.IsConstructCall()) {
749 Throw(args.GetIsolate(), "Worker must be constructed with new");
750 return;
751 }
752
753 {
754 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
755 if (workers_.length() >= kMaxWorkers) {
756 Throw(args.GetIsolate(), "Too many workers, I won't let you create more");
757 return;
758 }
759
760 // Initialize the internal field to NULL; if we return early without
761 // creating a new Worker (because the main thread is terminating) we can
762 // early-out from the instance calls.
763 args.Holder()->SetAlignedPointerInInternalField(0, NULL);
764
765 if (!allow_new_workers_) return;
766
767 Worker* worker = new Worker;
768 args.Holder()->SetAlignedPointerInInternalField(0, worker);
769 workers_.Add(worker);
770
771 String::Utf8Value script(args[0]);
772 if (!*script) {
773 Throw(args.GetIsolate(), "Can't get worker script");
774 return;
775 }
776 worker->StartExecuteInThread(*script);
777 }
778}
779
780
781void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
782 Isolate* isolate = args.GetIsolate();
783 HandleScope handle_scope(isolate);
784 Local<Context> context = isolate->GetCurrentContext();
785
786 if (args.Length() < 1) {
787 Throw(isolate, "Invalid argument");
788 return;
789 }
790
791 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
792 if (!worker) {
793 return;
794 }
795
796 Local<Value> message = args[0];
797 ObjectList to_transfer;
798 if (args.Length() >= 2) {
799 if (!args[1]->IsArray()) {
800 Throw(isolate, "Transfer list must be an Array");
801 return;
802 }
803
804 Local<Array> transfer = Local<Array>::Cast(args[1]);
805 uint32_t length = transfer->Length();
806 for (uint32_t i = 0; i < length; ++i) {
807 Local<Value> element;
808 if (transfer->Get(context, i).ToLocal(&element)) {
809 if (!element->IsArrayBuffer() && !element->IsSharedArrayBuffer()) {
810 Throw(isolate,
811 "Transfer array elements must be an ArrayBuffer or "
812 "SharedArrayBuffer.");
813 break;
814 }
815
816 to_transfer.Add(Local<Object>::Cast(element));
817 }
818 }
819 }
820
821 ObjectList seen_objects;
822 SerializationData* data = new SerializationData;
823 if (SerializeValue(isolate, message, to_transfer, &seen_objects, data)) {
824 worker->PostMessage(data);
825 } else {
826 delete data;
827 }
828}
829
830
831void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
832 Isolate* isolate = args.GetIsolate();
833 HandleScope handle_scope(isolate);
834 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
835 if (!worker) {
836 return;
837 }
838
839 SerializationData* data = worker->GetMessage();
840 if (data) {
841 int offset = 0;
842 Local<Value> data_value;
843 if (Shell::DeserializeValue(isolate, *data, &offset).ToLocal(&data_value)) {
844 args.GetReturnValue().Set(data_value);
845 }
846 delete data;
847 }
848}
849
850
851void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
852 Isolate* isolate = args.GetIsolate();
853 HandleScope handle_scope(isolate);
854 Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
855 if (!worker) {
856 return;
857 }
858
859 worker->Terminate();
860}
861#endif // !V8_SHARED
862
863
864void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
865 int exit_code = (*args)[0]
866 ->Int32Value(args->GetIsolate()->GetCurrentContext())
867 .FromMaybe(0);
868#ifndef V8_SHARED
869 CleanupWorkers();
870#endif // !V8_SHARED
871 OnExit(args->GetIsolate());
872 Exit(exit_code);
873}
874
875
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000876void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000877 base::CallOnce(&quit_once_, &QuitOnce,
878 const_cast<v8::FunctionCallbackInfo<v8::Value>*>(&args));
Steve Blocka7e24c12009-10-30 11:49:00 +0000879}
880
881
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000882void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
883 args.GetReturnValue().Set(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000884 String::NewFromUtf8(args.GetIsolate(), V8::GetVersion(),
885 NewStringType::kNormal).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000886}
887
888
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000889void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
890 HandleScope handle_scope(isolate);
891#ifndef V8_SHARED
Ben Murdochda12d292016-06-02 14:46:10 +0100892 Local<Context> context;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000893 bool enter_context = !isolate->InContext();
894 if (enter_context) {
Ben Murdochda12d292016-06-02 14:46:10 +0100895 context = Local<Context>::New(isolate, evaluation_context_);
896 context->Enter();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000897 }
898#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000899 v8::String::Utf8Value exception(try_catch->Exception());
900 const char* exception_string = ToCString(exception);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000901 Local<Message> message = try_catch->Message();
Steve Blocka7e24c12009-10-30 11:49:00 +0000902 if (message.IsEmpty()) {
903 // V8 didn't provide any extra information about this error; just
904 // print the exception.
905 printf("%s\n", exception_string);
906 } else {
907 // Print (filename):(line number): (message).
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000908 v8::String::Utf8Value filename(message->GetScriptOrigin().ResourceName());
Steve Blocka7e24c12009-10-30 11:49:00 +0000909 const char* filename_string = ToCString(filename);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000910 int linenum =
911 message->GetLineNumber(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000912 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
913 // Print line of source code.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000914 v8::String::Utf8Value sourceline(
915 message->GetSourceLine(isolate->GetCurrentContext()).ToLocalChecked());
Steve Blocka7e24c12009-10-30 11:49:00 +0000916 const char* sourceline_string = ToCString(sourceline);
917 printf("%s\n", sourceline_string);
918 // Print wavy underline (GetUnderline is deprecated).
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000919 int start =
920 message->GetStartColumn(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000921 for (int i = 0; i < start; i++) {
922 printf(" ");
923 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000924 int end = message->GetEndColumn(isolate->GetCurrentContext()).FromJust();
Steve Blocka7e24c12009-10-30 11:49:00 +0000925 for (int i = start; i < end; i++) {
926 printf("^");
927 }
928 printf("\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000929 Local<Value> stack_trace_string;
930 if (try_catch->StackTrace(isolate->GetCurrentContext())
931 .ToLocal(&stack_trace_string) &&
932 stack_trace_string->IsString()) {
933 v8::String::Utf8Value stack_trace(
934 Local<String>::Cast(stack_trace_string));
935 printf("%s\n", ToCString(stack_trace));
Ben Murdoch257744e2011-11-30 15:57:28 +0000936 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000937 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000938 printf("\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000939#ifndef V8_SHARED
Ben Murdochda12d292016-06-02 14:46:10 +0100940 if (enter_context) context->Exit();
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000941#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000942}
943
944
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000945#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000946int32_t* Counter::Bind(const char* name, bool is_histogram) {
947 int i;
948 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
949 name_[i] = static_cast<char>(name[i]);
950 name_[i] = '\0';
951 is_histogram_ = is_histogram;
952 return ptr();
953}
954
955
956void Counter::AddSample(int32_t sample) {
957 count_++;
958 sample_total_ += sample;
959}
960
961
962CounterCollection::CounterCollection() {
963 magic_number_ = 0xDEADFACE;
964 max_counters_ = kMaxCounters;
965 max_name_size_ = Counter::kMaxNameSize;
966 counters_in_use_ = 0;
967}
968
969
970Counter* CounterCollection::GetNextCounter() {
971 if (counters_in_use_ == kMaxCounters) return NULL;
972 return &counters_[counters_in_use_++];
973}
974
975
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000976void Shell::MapCounters(v8::Isolate* isolate, const char* name) {
977 counters_file_ = base::OS::MemoryMappedFile::create(
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000978 name, sizeof(CounterCollection), &local_counters_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000979 void* memory = (counters_file_ == NULL) ?
980 NULL : counters_file_->memory();
981 if (memory == NULL) {
982 printf("Could not map counters file %s\n", name);
Ben Murdoch589d6972011-11-30 16:04:58 +0000983 Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000984 }
985 counters_ = static_cast<CounterCollection*>(memory);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000986 isolate->SetCounterFunction(LookupCounter);
987 isolate->SetCreateHistogramFunction(CreateHistogram);
988 isolate->SetAddHistogramSampleFunction(AddHistogramSample);
Steve Blocka7e24c12009-10-30 11:49:00 +0000989}
990
991
992int CounterMap::Hash(const char* name) {
993 int h = 0;
994 int c;
995 while ((c = *name++) != 0) {
996 h += h << 5;
997 h += c;
998 }
999 return h;
1000}
1001
1002
1003Counter* Shell::GetCounter(const char* name, bool is_histogram) {
1004 Counter* counter = counter_map_->Lookup(name);
1005
1006 if (counter == NULL) {
1007 counter = counters_->GetNextCounter();
1008 if (counter != NULL) {
1009 counter_map_->Set(name, counter);
1010 counter->Bind(name, is_histogram);
1011 }
1012 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001013 DCHECK(counter->is_histogram() == is_histogram);
Steve Blocka7e24c12009-10-30 11:49:00 +00001014 }
1015 return counter;
1016}
1017
1018
1019int* Shell::LookupCounter(const char* name) {
1020 Counter* counter = GetCounter(name, false);
1021
1022 if (counter != NULL) {
1023 return counter->ptr();
1024 } else {
1025 return NULL;
1026 }
1027}
1028
1029
1030void* Shell::CreateHistogram(const char* name,
1031 int min,
1032 int max,
1033 size_t buckets) {
1034 return GetCounter(name, true);
1035}
1036
1037
1038void Shell::AddHistogramSample(void* histogram, int sample) {
1039 Counter* counter = reinterpret_cast<Counter*>(histogram);
1040 counter->AddSample(sample);
1041}
1042
Ben Murdochda12d292016-06-02 14:46:10 +01001043// Turn a value into a human-readable string.
1044Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
1045 v8::Local<v8::Context> context =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001046 v8::Local<v8::Context>::New(isolate, evaluation_context_);
Ben Murdochda12d292016-06-02 14:46:10 +01001047 if (stringify_function_.IsEmpty()) {
1048 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
1049 i::Vector<const char> source_string =
1050 i::NativesCollection<i::D8>::GetScriptSource(source_index);
1051 i::Vector<const char> source_name =
1052 i::NativesCollection<i::D8>::GetScriptName(source_index);
1053 Local<String> source =
1054 String::NewFromUtf8(isolate, source_string.start(),
1055 NewStringType::kNormal, source_string.length())
1056 .ToLocalChecked();
1057 Local<String> name =
1058 String::NewFromUtf8(isolate, source_name.start(),
1059 NewStringType::kNormal, source_name.length())
1060 .ToLocalChecked();
1061 ScriptOrigin origin(name);
1062 Local<Script> script =
1063 Script::Compile(context, source, &origin).ToLocalChecked();
1064 stringify_function_.Reset(
1065 isolate, script->Run(context).ToLocalChecked().As<Function>());
1066 }
1067 Local<Function> fun = Local<Function>::New(isolate, stringify_function_);
1068 Local<Value> argv[1] = {value};
1069 v8::TryCatch try_catch(isolate);
1070 MaybeLocal<Value> result =
1071 fun->Call(context, Undefined(isolate), 1, argv).ToLocalChecked();
1072 if (result.IsEmpty()) return String::Empty(isolate);
1073 return result.ToLocalChecked().As<String>();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001074}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001075#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001076
1077
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001078Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
1079 Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
1080 global_template->Set(
1081 String::NewFromUtf8(isolate, "print", NewStringType::kNormal)
1082 .ToLocalChecked(),
1083 FunctionTemplate::New(isolate, Print));
1084 global_template->Set(
1085 String::NewFromUtf8(isolate, "write", NewStringType::kNormal)
1086 .ToLocalChecked(),
1087 FunctionTemplate::New(isolate, Write));
1088 global_template->Set(
1089 String::NewFromUtf8(isolate, "read", NewStringType::kNormal)
1090 .ToLocalChecked(),
1091 FunctionTemplate::New(isolate, Read));
1092 global_template->Set(
1093 String::NewFromUtf8(isolate, "readbuffer", NewStringType::kNormal)
1094 .ToLocalChecked(),
1095 FunctionTemplate::New(isolate, ReadBuffer));
1096 global_template->Set(
1097 String::NewFromUtf8(isolate, "readline", NewStringType::kNormal)
1098 .ToLocalChecked(),
1099 FunctionTemplate::New(isolate, ReadLine));
1100 global_template->Set(
1101 String::NewFromUtf8(isolate, "load", NewStringType::kNormal)
1102 .ToLocalChecked(),
1103 FunctionTemplate::New(isolate, Load));
1104 // Some Emscripten-generated code tries to call 'quit', which in turn would
1105 // call C's exit(). This would lead to memory leaks, because there is no way
1106 // we can terminate cleanly then, so we need a way to hide 'quit'.
1107 if (!options.omit_quit) {
1108 global_template->Set(
1109 String::NewFromUtf8(isolate, "quit", NewStringType::kNormal)
1110 .ToLocalChecked(),
1111 FunctionTemplate::New(isolate, Quit));
1112 }
1113 global_template->Set(
1114 String::NewFromUtf8(isolate, "version", NewStringType::kNormal)
1115 .ToLocalChecked(),
1116 FunctionTemplate::New(isolate, Version));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001117
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001118 // Bind the Realm object.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001119 Local<ObjectTemplate> realm_template = ObjectTemplate::New(isolate);
1120 realm_template->Set(
1121 String::NewFromUtf8(isolate, "current", NewStringType::kNormal)
1122 .ToLocalChecked(),
1123 FunctionTemplate::New(isolate, RealmCurrent));
1124 realm_template->Set(
1125 String::NewFromUtf8(isolate, "owner", NewStringType::kNormal)
1126 .ToLocalChecked(),
1127 FunctionTemplate::New(isolate, RealmOwner));
1128 realm_template->Set(
1129 String::NewFromUtf8(isolate, "global", NewStringType::kNormal)
1130 .ToLocalChecked(),
1131 FunctionTemplate::New(isolate, RealmGlobal));
1132 realm_template->Set(
1133 String::NewFromUtf8(isolate, "create", NewStringType::kNormal)
1134 .ToLocalChecked(),
1135 FunctionTemplate::New(isolate, RealmCreate));
1136 realm_template->Set(
1137 String::NewFromUtf8(isolate, "dispose", NewStringType::kNormal)
1138 .ToLocalChecked(),
1139 FunctionTemplate::New(isolate, RealmDispose));
1140 realm_template->Set(
1141 String::NewFromUtf8(isolate, "switch", NewStringType::kNormal)
1142 .ToLocalChecked(),
1143 FunctionTemplate::New(isolate, RealmSwitch));
1144 realm_template->Set(
1145 String::NewFromUtf8(isolate, "eval", NewStringType::kNormal)
1146 .ToLocalChecked(),
1147 FunctionTemplate::New(isolate, RealmEval));
1148 realm_template->SetAccessor(
1149 String::NewFromUtf8(isolate, "shared", NewStringType::kNormal)
1150 .ToLocalChecked(),
1151 RealmSharedGet, RealmSharedSet);
1152 global_template->Set(
1153 String::NewFromUtf8(isolate, "Realm", NewStringType::kNormal)
1154 .ToLocalChecked(),
1155 realm_template);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001156
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001157#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001158 Local<ObjectTemplate> performance_template = ObjectTemplate::New(isolate);
1159 performance_template->Set(
1160 String::NewFromUtf8(isolate, "now", NewStringType::kNormal)
1161 .ToLocalChecked(),
1162 FunctionTemplate::New(isolate, PerformanceNow));
1163 global_template->Set(
1164 String::NewFromUtf8(isolate, "performance", NewStringType::kNormal)
1165 .ToLocalChecked(),
1166 performance_template);
1167
1168 Local<FunctionTemplate> worker_fun_template =
1169 FunctionTemplate::New(isolate, WorkerNew);
1170 Local<Signature> worker_signature =
1171 Signature::New(isolate, worker_fun_template);
1172 worker_fun_template->SetClassName(
1173 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1174 .ToLocalChecked());
1175 worker_fun_template->ReadOnlyPrototype();
1176 worker_fun_template->PrototypeTemplate()->Set(
1177 String::NewFromUtf8(isolate, "terminate", NewStringType::kNormal)
1178 .ToLocalChecked(),
1179 FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
1180 worker_signature));
1181 worker_fun_template->PrototypeTemplate()->Set(
1182 String::NewFromUtf8(isolate, "postMessage", NewStringType::kNormal)
1183 .ToLocalChecked(),
1184 FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
1185 worker_signature));
1186 worker_fun_template->PrototypeTemplate()->Set(
1187 String::NewFromUtf8(isolate, "getMessage", NewStringType::kNormal)
1188 .ToLocalChecked(),
1189 FunctionTemplate::New(isolate, WorkerGetMessage, Local<Value>(),
1190 worker_signature));
1191 worker_fun_template->InstanceTemplate()->SetInternalFieldCount(1);
1192 global_template->Set(
1193 String::NewFromUtf8(isolate, "Worker", NewStringType::kNormal)
1194 .ToLocalChecked(),
1195 worker_fun_template);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001196#endif // !V8_SHARED
1197
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001198 Local<ObjectTemplate> os_templ = ObjectTemplate::New(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001199 AddOSMethods(isolate, os_templ);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001200 global_template->Set(
1201 String::NewFromUtf8(isolate, "os", NewStringType::kNormal)
1202 .ToLocalChecked(),
1203 os_templ);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001204
1205 return global_template;
Steve Blocka7e24c12009-10-30 11:49:00 +00001206}
1207
Ben Murdoch097c5b22016-05-18 11:27:45 +01001208static void EmptyMessageCallback(Local<Message> message, Local<Value> error) {
1209 // Nothing to be done here, exceptions thrown up to the shell will be reported
1210 // separately by {Shell::ReportException} after they are caught.
1211}
Steve Blocka7e24c12009-10-30 11:49:00 +00001212
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001213void Shell::Initialize(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001214#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001215 // Set up counters
1216 if (i::StrLength(i::FLAG_map_counters) != 0)
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001217 MapCounters(isolate, i::FLAG_map_counters);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001218#endif // !V8_SHARED
Ben Murdoch097c5b22016-05-18 11:27:45 +01001219 // Disable default message reporting.
1220 isolate->AddMessageListener(EmptyMessageCallback);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001221}
1222
1223
1224Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001225#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001226 // This needs to be a critical section since this is not thread-safe
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001227 base::LockGuard<base::Mutex> lock_guard(context_mutex_.Pointer());
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001228#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001229 // Initialize the global objects
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001230 Local<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001231 EscapableHandleScope handle_scope(isolate);
1232 Local<Context> context = Context::New(isolate, NULL, global_template);
1233 DCHECK(!context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001234 Context::Scope scope(context);
1235
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001236#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001237 i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001238 i::JSArguments js_args = i::FLAG_js_arguments;
1239 i::Handle<i::FixedArray> arguments_array =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001240 factory->NewFixedArray(js_args.argc);
1241 for (int j = 0; j < js_args.argc; j++) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001242 i::Handle<i::String> arg =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001243 factory->NewStringFromUtf8(i::CStrVector(js_args[j])).ToHandleChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001244 arguments_array->set(j, *arg);
1245 }
1246 i::Handle<i::JSArray> arguments_jsarray =
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001247 factory->NewJSArrayWithElements(arguments_array);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001248 context->Global()
1249 ->Set(context,
1250 String::NewFromUtf8(isolate, "arguments", NewStringType::kNormal)
1251 .ToLocalChecked(),
1252 Utils::ToLocal(arguments_jsarray))
1253 .FromJust();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001254#endif // !V8_SHARED
1255 return handle_scope.Escape(context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001256}
1257
1258
Ben Murdoch589d6972011-11-30 16:04:58 +00001259void Shell::Exit(int exit_code) {
1260 // Use _exit instead of exit to avoid races between isolate
1261 // threads and static destructors.
1262 fflush(stdout);
1263 fflush(stderr);
1264 _exit(exit_code);
1265}
1266
1267
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001268#ifndef V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001269struct CounterAndKey {
1270 Counter* counter;
1271 const char* key;
1272};
1273
1274
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001275inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
1276 return strcmp(lhs.key, rhs.key) < 0;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001277}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001278#endif // !V8_SHARED
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001279
1280
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001281void Shell::OnExit(v8::Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001282#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001283 if (i::FLAG_dump_counters) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001284 int number_of_counters = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001285 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001286 number_of_counters++;
1287 }
1288 CounterAndKey* counters = new CounterAndKey[number_of_counters];
1289 int j = 0;
1290 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
1291 counters[j].counter = i.CurrentValue();
1292 counters[j].key = i.CurrentKey();
1293 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001294 std::sort(counters, counters + number_of_counters);
1295 printf("+----------------------------------------------------------------+"
1296 "-------------+\n");
1297 printf("| Name |"
1298 " Value |\n");
1299 printf("+----------------------------------------------------------------+"
1300 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001301 for (j = 0; j < number_of_counters; j++) {
1302 Counter* counter = counters[j].counter;
1303 const char* key = counters[j].key;
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 if (counter->is_histogram()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001305 printf("| c:%-60s | %11i |\n", key, counter->count());
1306 printf("| t:%-60s | %11i |\n", key, counter->sample_total());
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001308 printf("| %-62s | %11i |\n", key, counter->count());
Steve Blocka7e24c12009-10-30 11:49:00 +00001309 }
1310 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001311 printf("+----------------------------------------------------------------+"
1312 "-------------+\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001313 delete [] counters;
Steve Blocka7e24c12009-10-30 11:49:00 +00001314 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001315 delete counters_file_;
1316 delete counter_map_;
1317#endif // !V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001318}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001319
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001320
1321
1322static FILE* FOpen(const char* path, const char* mode) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001323#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001324 FILE* result;
1325 if (fopen_s(&result, path, mode) == 0) {
1326 return result;
1327 } else {
1328 return NULL;
1329 }
1330#else
1331 FILE* file = fopen(path, mode);
1332 if (file == NULL) return NULL;
1333 struct stat file_stat;
1334 if (fstat(fileno(file), &file_stat) != 0) return NULL;
1335 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
1336 if (is_regular_file) return file;
1337 fclose(file);
1338 return NULL;
1339#endif
1340}
Steve Blocka7e24c12009-10-30 11:49:00 +00001341
1342
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001343static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001344 FILE* file = FOpen(name, "rb");
Steve Blocka7e24c12009-10-30 11:49:00 +00001345 if (file == NULL) return NULL;
1346
1347 fseek(file, 0, SEEK_END);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001348 size_t size = ftell(file);
Steve Blocka7e24c12009-10-30 11:49:00 +00001349 rewind(file);
1350
1351 char* chars = new char[size + 1];
1352 chars[size] = '\0';
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001353 for (size_t i = 0; i < size;) {
1354 i += fread(&chars[i], 1, size - i, file);
1355 if (ferror(file)) {
1356 fclose(file);
1357 delete[] chars;
1358 return nullptr;
1359 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001360 }
1361 fclose(file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001362 *size_out = static_cast<int>(size);
Steve Blocka7e24c12009-10-30 11:49:00 +00001363 return chars;
1364}
1365
1366
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001367struct DataAndPersistent {
1368 uint8_t* data;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001369 int byte_length;
1370 Global<ArrayBuffer> handle;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001371};
1372
1373
1374static void ReadBufferWeakCallback(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001375 const v8::WeakCallbackInfo<DataAndPersistent>& data) {
1376 int byte_length = data.GetParameter()->byte_length;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001377 data.GetIsolate()->AdjustAmountOfExternalAllocatedMemory(
1378 -static_cast<intptr_t>(byte_length));
1379
1380 delete[] data.GetParameter()->data;
1381 data.GetParameter()->handle.Reset();
1382 delete data.GetParameter();
1383}
1384
1385
1386void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
1387 DCHECK(sizeof(char) == sizeof(uint8_t)); // NOLINT
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001388 String::Utf8Value filename(args[0]);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001389 int length;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001390 if (*filename == NULL) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001391 Throw(args.GetIsolate(), "Error loading file");
1392 return;
Steve Blocka7e24c12009-10-30 11:49:00 +00001393 }
1394
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001395 Isolate* isolate = args.GetIsolate();
1396 DataAndPersistent* data = new DataAndPersistent;
1397 data->data = reinterpret_cast<uint8_t*>(
1398 ReadChars(args.GetIsolate(), *filename, &length));
1399 if (data->data == NULL) {
1400 delete data;
1401 Throw(args.GetIsolate(), "Error reading file");
1402 return;
1403 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001404 data->byte_length = length;
1405 Local<v8::ArrayBuffer> buffer = ArrayBuffer::New(isolate, data->data, length);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001406 data->handle.Reset(isolate, buffer);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001407 data->handle.SetWeak(data, ReadBufferWeakCallback,
1408 v8::WeakCallbackType::kParameter);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001409 data->handle.MarkIndependent();
1410 isolate->AdjustAmountOfExternalAllocatedMemory(length);
1411
1412 args.GetReturnValue().Set(buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00001413}
1414
1415
Steve Blocka7e24c12009-10-30 11:49:00 +00001416// Reads a file into a v8 string.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001417Local<String> Shell::ReadFile(Isolate* isolate, const char* name) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001418 int size = 0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001419 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001420 if (chars == NULL) return Local<String>();
1421 Local<String> result =
1422 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1423 .ToLocalChecked();
Steve Blocka7e24c12009-10-30 11:49:00 +00001424 delete[] chars;
1425 return result;
1426}
1427
1428
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001429void Shell::RunShell(Isolate* isolate) {
1430 HandleScope outer_scope(isolate);
1431 v8::Local<v8::Context> context =
1432 v8::Local<v8::Context>::New(isolate, evaluation_context_);
1433 v8::Context::Scope context_scope(context);
1434 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001435 Local<String> name =
1436 String::NewFromUtf8(isolate, "(d8)", NewStringType::kNormal)
1437 .ToLocalChecked();
1438 printf("V8 version %s\n", V8::GetVersion());
Steve Blocka7e24c12009-10-30 11:49:00 +00001439 while (true) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001440 HandleScope inner_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001441 printf("d8> ");
1442#if defined(__native_client__)
1443 // Native Client libc is used to being embedded in Chrome and
1444 // has trouble recognizing when to flush.
1445 fflush(stdout);
1446#endif
1447 Local<String> input = Shell::ReadFromStdin(isolate);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001448 if (input.IsEmpty()) break;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001449 ExecuteString(isolate, input, name, true, true);
Steve Blocka7e24c12009-10-30 11:49:00 +00001450 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001451 printf("\n");
1452}
1453
1454
Ben Murdoch589d6972011-11-30 16:04:58 +00001455SourceGroup::~SourceGroup() {
1456#ifndef V8_SHARED
Ben Murdoch589d6972011-11-30 16:04:58 +00001457 delete thread_;
1458 thread_ = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001459#endif // !V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001460}
Steve Blocka7e24c12009-10-30 11:49:00 +00001461
Steve Blocka7e24c12009-10-30 11:49:00 +00001462
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001463void SourceGroup::Execute(Isolate* isolate) {
1464 bool exception_was_thrown = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001465 for (int i = begin_offset_; i < end_offset_; ++i) {
1466 const char* arg = argv_[i];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001467 Shell::SourceType source_type = Shell::SCRIPT;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001468 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1469 // Execute argument given to -e option directly.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001470 HandleScope handle_scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001471 Local<String> file_name =
1472 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1473 .ToLocalChecked();
1474 Local<String> source =
1475 String::NewFromUtf8(isolate, argv_[i + 1], NewStringType::kNormal)
1476 .ToLocalChecked();
1477 Shell::options.script_executed = true;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001478 if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1479 exception_was_thrown = true;
1480 break;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001481 }
1482 ++i;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001483 continue;
1484 } else if (strcmp(arg, "--module") == 0 && i + 1 < end_offset_) {
1485 // Treat the next file as a module.
1486 source_type = Shell::MODULE;
1487 arg = argv_[++i];
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001488 } else if (arg[0] == '-') {
1489 // Ignore other options. They have been parsed already.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001490 continue;
1491 }
1492
1493 // Use all other arguments as names of files to load and run.
1494 HandleScope handle_scope(isolate);
1495 Local<String> file_name =
1496 String::NewFromUtf8(isolate, arg, NewStringType::kNormal)
1497 .ToLocalChecked();
1498 Local<String> source = ReadFile(isolate, arg);
1499 if (source.IsEmpty()) {
1500 printf("Error reading '%s'\n", arg);
1501 Shell::Exit(1);
1502 }
1503 Shell::options.script_executed = true;
1504 if (!Shell::ExecuteString(isolate, source, file_name, false, true,
1505 source_type)) {
1506 exception_was_thrown = true;
1507 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001508 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001509 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001510 if (exception_was_thrown != Shell::options.expected_to_throw) {
1511 Shell::Exit(1);
1512 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001513}
Steve Blocka7e24c12009-10-30 11:49:00 +00001514
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001515
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001516Local<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001517 int size;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001518 char* chars = ReadChars(isolate, name, &size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001519 if (chars == NULL) return Local<String>();
1520 Local<String> result =
1521 String::NewFromUtf8(isolate, chars, NewStringType::kNormal, size)
1522 .ToLocalChecked();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001523 delete[] chars;
1524 return result;
1525}
1526
1527
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001528#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001529base::Thread::Options SourceGroup::GetThreadOptions() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001530 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1531 // which is not enough to parse the big literal expressions used in tests.
1532 // The stack size should be at least StackGuard::kLimitSize + some
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001533 // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001534 return base::Thread::Options("IsolateThread", 2 * MB);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001535}
1536
1537
1538void SourceGroup::ExecuteInThread() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001539 Isolate::CreateParams create_params;
1540 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1541 Isolate* isolate = Isolate::New(create_params);
1542 for (int i = 0; i < Shell::options.stress_runs; ++i) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001543 next_semaphore_.Wait();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001544 {
1545 Isolate::Scope iscope(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001546 {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001547 HandleScope scope(isolate);
1548 PerIsolateData data(isolate);
1549 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1550 {
1551 Context::Scope cscope(context);
1552 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1553 Execute(isolate);
1554 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001555 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001556 Shell::CollectGarbage(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001557 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001558 done_semaphore_.Signal();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001559 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001560
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001561 isolate->Dispose();
1562}
1563
1564
1565void SourceGroup::StartExecuteInThread() {
1566 if (thread_ == NULL) {
1567 thread_ = new IsolateThread(this);
1568 thread_->Start();
1569 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001570 next_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001571}
1572
1573
1574void SourceGroup::WaitForThread() {
1575 if (thread_ == NULL) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001576 done_semaphore_.Wait();
1577}
1578
1579
1580void SourceGroup::JoinThread() {
1581 if (thread_ == NULL) return;
1582 thread_->Join();
1583}
1584
1585
1586SerializationData::~SerializationData() {
1587 // Any ArrayBuffer::Contents are owned by this SerializationData object if
1588 // ownership hasn't been transferred out via ReadArrayBufferContents.
1589 // SharedArrayBuffer::Contents may be used by multiple threads, so must be
1590 // cleaned up by the main thread in Shell::CleanupWorkers().
1591 for (int i = 0; i < array_buffer_contents_.length(); ++i) {
1592 ArrayBuffer::Contents& contents = array_buffer_contents_[i];
1593 if (contents.Data()) {
1594 Shell::array_buffer_allocator->Free(contents.Data(),
1595 contents.ByteLength());
1596 }
1597 }
1598}
1599
1600
1601void SerializationData::WriteTag(SerializationTag tag) { data_.Add(tag); }
1602
1603
1604void SerializationData::WriteMemory(const void* p, int length) {
1605 if (length > 0) {
1606 i::Vector<uint8_t> block = data_.AddBlock(0, length);
1607 memcpy(&block[0], p, length);
1608 }
1609}
1610
1611
1612void SerializationData::WriteArrayBufferContents(
1613 const ArrayBuffer::Contents& contents) {
1614 array_buffer_contents_.Add(contents);
1615 WriteTag(kSerializationTagTransferredArrayBuffer);
1616 int index = array_buffer_contents_.length() - 1;
1617 Write(index);
1618}
1619
1620
1621void SerializationData::WriteSharedArrayBufferContents(
1622 const SharedArrayBuffer::Contents& contents) {
1623 shared_array_buffer_contents_.Add(contents);
1624 WriteTag(kSerializationTagTransferredSharedArrayBuffer);
1625 int index = shared_array_buffer_contents_.length() - 1;
1626 Write(index);
1627}
1628
1629
1630SerializationTag SerializationData::ReadTag(int* offset) const {
1631 return static_cast<SerializationTag>(Read<uint8_t>(offset));
1632}
1633
1634
1635void SerializationData::ReadMemory(void* p, int length, int* offset) const {
1636 if (length > 0) {
1637 memcpy(p, &data_[*offset], length);
1638 (*offset) += length;
1639 }
1640}
1641
1642
1643void SerializationData::ReadArrayBufferContents(ArrayBuffer::Contents* contents,
1644 int* offset) const {
1645 int index = Read<int>(offset);
1646 DCHECK(index < array_buffer_contents_.length());
1647 *contents = array_buffer_contents_[index];
1648 // Ownership of this ArrayBuffer::Contents is passed to the caller. Neuter
1649 // our copy so it won't be double-free'd when this SerializationData is
1650 // destroyed.
1651 array_buffer_contents_[index] = ArrayBuffer::Contents();
1652}
1653
1654
1655void SerializationData::ReadSharedArrayBufferContents(
1656 SharedArrayBuffer::Contents* contents, int* offset) const {
1657 int index = Read<int>(offset);
1658 DCHECK(index < shared_array_buffer_contents_.length());
1659 *contents = shared_array_buffer_contents_[index];
1660}
1661
1662
1663void SerializationDataQueue::Enqueue(SerializationData* data) {
1664 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1665 data_.Add(data);
1666}
1667
1668
1669bool SerializationDataQueue::Dequeue(SerializationData** data) {
1670 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1671 *data = NULL;
1672 if (data_.is_empty()) return false;
1673 *data = data_.Remove(0);
1674 return true;
1675}
1676
1677
1678bool SerializationDataQueue::IsEmpty() {
1679 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1680 return data_.is_empty();
1681}
1682
1683
1684void SerializationDataQueue::Clear() {
1685 base::LockGuard<base::Mutex> lock_guard(&mutex_);
1686 for (int i = 0; i < data_.length(); ++i) {
1687 delete data_[i];
1688 }
1689 data_.Clear();
1690}
1691
1692
1693Worker::Worker()
1694 : in_semaphore_(0),
1695 out_semaphore_(0),
1696 thread_(NULL),
1697 script_(NULL),
1698 running_(false) {}
1699
1700
1701Worker::~Worker() {
1702 delete thread_;
1703 thread_ = NULL;
1704 delete[] script_;
1705 script_ = NULL;
1706 in_queue_.Clear();
1707 out_queue_.Clear();
1708}
1709
1710
1711void Worker::StartExecuteInThread(const char* script) {
1712 running_ = true;
1713 script_ = i::StrDup(script);
1714 thread_ = new WorkerThread(this);
1715 thread_->Start();
1716}
1717
1718
1719void Worker::PostMessage(SerializationData* data) {
1720 in_queue_.Enqueue(data);
1721 in_semaphore_.Signal();
1722}
1723
1724
1725SerializationData* Worker::GetMessage() {
1726 SerializationData* data = NULL;
1727 while (!out_queue_.Dequeue(&data)) {
1728 // If the worker is no longer running, and there are no messages in the
1729 // queue, don't expect any more messages from it.
1730 if (!base::NoBarrier_Load(&running_)) break;
1731 out_semaphore_.Wait();
1732 }
1733 return data;
1734}
1735
1736
1737void Worker::Terminate() {
1738 base::NoBarrier_Store(&running_, false);
1739 // Post NULL to wake the Worker thread message loop, and tell it to stop
1740 // running.
1741 PostMessage(NULL);
1742}
1743
1744
1745void Worker::WaitForThread() {
1746 Terminate();
1747 thread_->Join();
1748}
1749
1750
1751void Worker::ExecuteInThread() {
1752 Isolate::CreateParams create_params;
1753 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
1754 Isolate* isolate = Isolate::New(create_params);
1755 {
1756 Isolate::Scope iscope(isolate);
1757 {
1758 HandleScope scope(isolate);
1759 PerIsolateData data(isolate);
1760 Local<Context> context = Shell::CreateEvaluationContext(isolate);
1761 {
1762 Context::Scope cscope(context);
1763 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1764
1765 Local<Object> global = context->Global();
1766 Local<Value> this_value = External::New(isolate, this);
1767 Local<FunctionTemplate> postmessage_fun_template =
1768 FunctionTemplate::New(isolate, PostMessageOut, this_value);
1769
1770 Local<Function> postmessage_fun;
1771 if (postmessage_fun_template->GetFunction(context)
1772 .ToLocal(&postmessage_fun)) {
1773 global->Set(context, String::NewFromUtf8(isolate, "postMessage",
1774 NewStringType::kNormal)
1775 .ToLocalChecked(),
1776 postmessage_fun).FromJust();
1777 }
1778
1779 // First run the script
1780 Local<String> file_name =
1781 String::NewFromUtf8(isolate, "unnamed", NewStringType::kNormal)
1782 .ToLocalChecked();
1783 Local<String> source =
1784 String::NewFromUtf8(isolate, script_, NewStringType::kNormal)
1785 .ToLocalChecked();
1786 if (Shell::ExecuteString(isolate, source, file_name, false, true)) {
1787 // Get the message handler
1788 Local<Value> onmessage =
1789 global->Get(context, String::NewFromUtf8(isolate, "onmessage",
1790 NewStringType::kNormal)
1791 .ToLocalChecked()).ToLocalChecked();
1792 if (onmessage->IsFunction()) {
1793 Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
1794 // Now wait for messages
1795 while (true) {
1796 in_semaphore_.Wait();
1797 SerializationData* data;
1798 if (!in_queue_.Dequeue(&data)) continue;
1799 if (data == NULL) {
1800 break;
1801 }
1802 int offset = 0;
1803 Local<Value> data_value;
1804 if (Shell::DeserializeValue(isolate, *data, &offset)
1805 .ToLocal(&data_value)) {
1806 Local<Value> argv[] = {data_value};
1807 (void)onmessage_fun->Call(context, global, 1, argv);
1808 }
1809 delete data;
1810 }
1811 }
1812 }
1813 }
1814 }
1815 Shell::CollectGarbage(isolate);
1816 }
1817 isolate->Dispose();
1818
1819 // Post NULL to wake the thread waiting on GetMessage() if there is one.
1820 out_queue_.Enqueue(NULL);
1821 out_semaphore_.Signal();
1822}
1823
1824
1825void Worker::PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args) {
1826 Isolate* isolate = args.GetIsolate();
1827 HandleScope handle_scope(isolate);
1828
1829 if (args.Length() < 1) {
1830 Throw(isolate, "Invalid argument");
1831 return;
1832 }
1833
1834 Local<Value> message = args[0];
1835
1836 // TODO(binji): Allow transferring from worker to main thread?
1837 Shell::ObjectList to_transfer;
1838
1839 Shell::ObjectList seen_objects;
1840 SerializationData* data = new SerializationData;
1841 if (Shell::SerializeValue(isolate, message, to_transfer, &seen_objects,
1842 data)) {
1843 DCHECK(args.Data()->IsExternal());
1844 Local<External> this_value = Local<External>::Cast(args.Data());
1845 Worker* worker = static_cast<Worker*>(this_value->Value());
1846 worker->out_queue_.Enqueue(data);
1847 worker->out_semaphore_.Signal();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001848 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001849 delete data;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001850 }
1851}
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001852#endif // !V8_SHARED
1853
1854
1855void SetFlagsFromString(const char* flags) {
1856 v8::V8::SetFlagsFromString(flags, static_cast<int>(strlen(flags)));
1857}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001858
1859
1860bool Shell::SetOptions(int argc, char* argv[]) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001861 bool logfile_per_isolate = false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001862 for (int i = 0; i < argc; i++) {
1863 if (strcmp(argv[i], "--stress-opt") == 0) {
1864 options.stress_opt = true;
1865 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001866 } else if (strcmp(argv[i], "--nostress-opt") == 0) {
1867 options.stress_opt = false;
1868 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001869 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1870 options.stress_deopt = true;
1871 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001872 } else if (strcmp(argv[i], "--mock-arraybuffer-allocator") == 0) {
1873 options.mock_arraybuffer_allocator = true;
1874 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001875 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1876 // No support for stressing if we can't use --always-opt.
1877 options.stress_opt = false;
1878 options.stress_deopt = false;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001879 } else if (strcmp(argv[i], "--logfile-per-isolate") == 0) {
1880 logfile_per_isolate = true;
1881 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001882 } else if (strcmp(argv[i], "--shell") == 0) {
1883 options.interactive_shell = true;
1884 argv[i] = NULL;
1885 } else if (strcmp(argv[i], "--test") == 0) {
1886 options.test_shell = true;
1887 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001888 } else if (strcmp(argv[i], "--notest") == 0 ||
1889 strcmp(argv[i], "--no-test") == 0) {
1890 options.test_shell = false;
1891 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001892 } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
1893 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001894 argv[i] = NULL;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001895 } else if (strcmp(argv[i], "--invoke-weak-callbacks") == 0) {
1896 options.invoke_weak_callbacks = true;
1897 // TODO(jochen) See issue 3351
1898 options.send_idle_notification = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001899 argv[i] = NULL;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001900 } else if (strcmp(argv[i], "--omit-quit") == 0) {
1901 options.omit_quit = true;
1902 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001903 } else if (strcmp(argv[i], "-f") == 0) {
1904 // Ignore any -f flags for compatibility with other stand-alone
1905 // JavaScript engines.
1906 continue;
1907 } else if (strcmp(argv[i], "--isolate") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001908#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001909 printf("D8 with shared library does not support multi-threading\n");
1910 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001911#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001912 options.num_isolates++;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001913 } else if (strcmp(argv[i], "--dump-heap-constants") == 0) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001914#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001915 printf("D8 with shared library does not support constant dumping\n");
Ben Murdoch589d6972011-11-30 16:04:58 +00001916 return false;
1917#else
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001918 options.dump_heap_constants = true;
1919 argv[i] = NULL;
Ben Murdoch589d6972011-11-30 16:04:58 +00001920#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001921 } else if (strcmp(argv[i], "--throws") == 0) {
1922 options.expected_to_throw = true;
1923 argv[i] = NULL;
1924 } else if (strncmp(argv[i], "--icu-data-file=", 16) == 0) {
1925 options.icu_data_file = argv[i] + 16;
1926 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001927#ifdef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001928 } else if (strcmp(argv[i], "--dump-counters") == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001929 printf("D8 with shared library does not include counters\n");
1930 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001931#endif // V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001932#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1933 } else if (strncmp(argv[i], "--natives_blob=", 15) == 0) {
1934 options.natives_blob = argv[i] + 15;
1935 argv[i] = NULL;
1936 } else if (strncmp(argv[i], "--snapshot_blob=", 16) == 0) {
1937 options.snapshot_blob = argv[i] + 16;
1938 argv[i] = NULL;
1939#endif // V8_USE_EXTERNAL_STARTUP_DATA
1940 } else if (strcmp(argv[i], "--cache") == 0 ||
1941 strncmp(argv[i], "--cache=", 8) == 0) {
1942 const char* value = argv[i] + 7;
1943 if (!*value || strncmp(value, "=code", 6) == 0) {
1944 options.compile_options = v8::ScriptCompiler::kProduceCodeCache;
1945 } else if (strncmp(value, "=parse", 7) == 0) {
1946 options.compile_options = v8::ScriptCompiler::kProduceParserCache;
1947 } else if (strncmp(value, "=none", 6) == 0) {
1948 options.compile_options = v8::ScriptCompiler::kNoCompileOptions;
1949 } else {
1950 printf("Unknown option to --cache.\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001951 return false;
1952 }
1953 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001954 }
1955 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001956
1957 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1958
Ben Murdoch589d6972011-11-30 16:04:58 +00001959 // Set up isolated source groups.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001960 options.isolate_sources = new SourceGroup[options.num_isolates];
1961 SourceGroup* current = options.isolate_sources;
1962 current->Begin(argv, 1);
1963 for (int i = 1; i < argc; i++) {
1964 const char* str = argv[i];
1965 if (strcmp(str, "--isolate") == 0) {
1966 current->End(i);
1967 current++;
1968 current->Begin(argv, i + 1);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001969 } else if (strcmp(str, "--module") == 0) {
1970 // Pass on to SourceGroup, which understands this option.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001971 } else if (strncmp(argv[i], "--", 2) == 0) {
1972 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001973 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
1974 options.script_executed = true;
1975 } else if (strncmp(str, "-", 1) != 0) {
1976 // Not a flag, so it must be a script to execute.
1977 options.script_executed = true;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001978 }
1979 }
1980 current->End(argc);
1981
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001982 if (!logfile_per_isolate && options.num_isolates) {
1983 SetFlagsFromString("--nologfile_per_isolate");
1984 }
1985
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001986 return true;
1987}
1988
1989
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001990int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001991#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001992 for (int i = 1; i < options.num_isolates; ++i) {
1993 options.isolate_sources[i].StartExecuteInThread();
1994 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001995#endif // !V8_SHARED
1996 {
1997 HandleScope scope(isolate);
1998 Local<Context> context = CreateEvaluationContext(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001999 if (last_run && options.use_interactive_shell()) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +01002000 // Keep using the same context in the interactive shell.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002001 evaluation_context_.Reset(isolate, context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002002 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002003 {
2004 Context::Scope cscope(context);
2005 PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
2006 options.isolate_sources[0].Execute(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002007 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002008 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002009 CollectGarbage(isolate);
2010#ifndef V8_SHARED
2011 for (int i = 1; i < options.num_isolates; ++i) {
2012 if (last_run) {
2013 options.isolate_sources[i].JoinThread();
2014 } else {
2015 options.isolate_sources[i].WaitForThread();
2016 }
2017 }
2018 CleanupWorkers();
2019#endif // !V8_SHARED
2020 return 0;
2021}
2022
2023
2024void Shell::CollectGarbage(Isolate* isolate) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002025 if (options.send_idle_notification) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002026 const double kLongIdlePauseInSeconds = 1.0;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002027 isolate->ContextDisposedNotification();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002028 isolate->IdleNotificationDeadline(
2029 g_platform->MonotonicallyIncreasingTime() + kLongIdlePauseInSeconds);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002030 }
2031 if (options.invoke_weak_callbacks) {
2032 // By sending a low memory notifications, we will try hard to collect all
2033 // garbage and will therefore also invoke all weak callbacks of actually
2034 // unreachable persistent handles.
2035 isolate->LowMemoryNotification();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002036 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002037}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002038
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002039
2040void Shell::EmptyMessageQueues(Isolate* isolate) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002041#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002042 if (!i::FLAG_verify_predictable) {
2043#endif
2044 while (v8::platform::PumpMessageLoop(g_platform, isolate)) continue;
2045#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002046 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002047#endif
Steve Blocka7e24c12009-10-30 11:49:00 +00002048}
2049
2050
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002051#ifndef V8_SHARED
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002052bool Shell::SerializeValue(Isolate* isolate, Local<Value> value,
2053 const ObjectList& to_transfer,
2054 ObjectList* seen_objects,
2055 SerializationData* out_data) {
2056 DCHECK(out_data);
2057 Local<Context> context = isolate->GetCurrentContext();
2058
2059 if (value->IsUndefined()) {
2060 out_data->WriteTag(kSerializationTagUndefined);
2061 } else if (value->IsNull()) {
2062 out_data->WriteTag(kSerializationTagNull);
2063 } else if (value->IsTrue()) {
2064 out_data->WriteTag(kSerializationTagTrue);
2065 } else if (value->IsFalse()) {
2066 out_data->WriteTag(kSerializationTagFalse);
2067 } else if (value->IsNumber()) {
2068 Local<Number> num = Local<Number>::Cast(value);
2069 double value = num->Value();
2070 out_data->WriteTag(kSerializationTagNumber);
2071 out_data->Write(value);
2072 } else if (value->IsString()) {
2073 v8::String::Utf8Value str(value);
2074 out_data->WriteTag(kSerializationTagString);
2075 out_data->Write(str.length());
2076 out_data->WriteMemory(*str, str.length());
2077 } else if (value->IsArray()) {
2078 Local<Array> array = Local<Array>::Cast(value);
2079 if (FindInObjectList(array, *seen_objects)) {
2080 Throw(isolate, "Duplicated arrays not supported");
2081 return false;
2082 }
2083 seen_objects->Add(array);
2084 out_data->WriteTag(kSerializationTagArray);
2085 uint32_t length = array->Length();
2086 out_data->Write(length);
2087 for (uint32_t i = 0; i < length; ++i) {
2088 Local<Value> element_value;
2089 if (array->Get(context, i).ToLocal(&element_value)) {
2090 if (!SerializeValue(isolate, element_value, to_transfer, seen_objects,
2091 out_data))
2092 return false;
2093 } else {
2094 Throw(isolate, "Failed to serialize array element.");
2095 return false;
2096 }
2097 }
2098 } else if (value->IsArrayBuffer()) {
2099 Local<ArrayBuffer> array_buffer = Local<ArrayBuffer>::Cast(value);
2100 if (FindInObjectList(array_buffer, *seen_objects)) {
2101 Throw(isolate, "Duplicated array buffers not supported");
2102 return false;
2103 }
2104 seen_objects->Add(array_buffer);
2105 if (FindInObjectList(array_buffer, to_transfer)) {
2106 // Transfer ArrayBuffer
2107 if (!array_buffer->IsNeuterable()) {
2108 Throw(isolate, "Attempting to transfer an un-neuterable ArrayBuffer");
2109 return false;
2110 }
2111
2112 ArrayBuffer::Contents contents = array_buffer->IsExternal()
2113 ? array_buffer->GetContents()
2114 : array_buffer->Externalize();
2115 array_buffer->Neuter();
2116 out_data->WriteArrayBufferContents(contents);
2117 } else {
2118 ArrayBuffer::Contents contents = array_buffer->GetContents();
2119 // Clone ArrayBuffer
2120 if (contents.ByteLength() > i::kMaxInt) {
2121 Throw(isolate, "ArrayBuffer is too big to clone");
2122 return false;
2123 }
2124
2125 int32_t byte_length = static_cast<int32_t>(contents.ByteLength());
2126 out_data->WriteTag(kSerializationTagArrayBuffer);
2127 out_data->Write(byte_length);
2128 out_data->WriteMemory(contents.Data(), byte_length);
2129 }
2130 } else if (value->IsSharedArrayBuffer()) {
2131 Local<SharedArrayBuffer> sab = Local<SharedArrayBuffer>::Cast(value);
2132 if (FindInObjectList(sab, *seen_objects)) {
2133 Throw(isolate, "Duplicated shared array buffers not supported");
2134 return false;
2135 }
2136 seen_objects->Add(sab);
2137 if (!FindInObjectList(sab, to_transfer)) {
2138 Throw(isolate, "SharedArrayBuffer must be transferred");
2139 return false;
2140 }
2141
2142 SharedArrayBuffer::Contents contents;
2143 if (sab->IsExternal()) {
2144 contents = sab->GetContents();
2145 } else {
2146 contents = sab->Externalize();
2147 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2148 externalized_shared_contents_.Add(contents);
2149 }
2150 out_data->WriteSharedArrayBufferContents(contents);
2151 } else if (value->IsObject()) {
2152 Local<Object> object = Local<Object>::Cast(value);
2153 if (FindInObjectList(object, *seen_objects)) {
2154 Throw(isolate, "Duplicated objects not supported");
2155 return false;
2156 }
2157 seen_objects->Add(object);
2158 Local<Array> property_names;
2159 if (!object->GetOwnPropertyNames(context).ToLocal(&property_names)) {
2160 Throw(isolate, "Unable to get property names");
2161 return false;
2162 }
2163
2164 uint32_t length = property_names->Length();
2165 out_data->WriteTag(kSerializationTagObject);
2166 out_data->Write(length);
2167 for (uint32_t i = 0; i < length; ++i) {
2168 Local<Value> name;
2169 Local<Value> property_value;
2170 if (property_names->Get(context, i).ToLocal(&name) &&
2171 object->Get(context, name).ToLocal(&property_value)) {
2172 if (!SerializeValue(isolate, name, to_transfer, seen_objects, out_data))
2173 return false;
2174 if (!SerializeValue(isolate, property_value, to_transfer, seen_objects,
2175 out_data))
2176 return false;
2177 } else {
2178 Throw(isolate, "Failed to serialize property.");
2179 return false;
2180 }
2181 }
2182 } else {
2183 Throw(isolate, "Don't know how to serialize object");
2184 return false;
2185 }
2186
2187 return true;
2188}
2189
2190
2191MaybeLocal<Value> Shell::DeserializeValue(Isolate* isolate,
2192 const SerializationData& data,
2193 int* offset) {
2194 DCHECK(offset);
2195 EscapableHandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002196 Local<Value> result;
2197 SerializationTag tag = data.ReadTag(offset);
2198
2199 switch (tag) {
2200 case kSerializationTagUndefined:
2201 result = Undefined(isolate);
2202 break;
2203 case kSerializationTagNull:
2204 result = Null(isolate);
2205 break;
2206 case kSerializationTagTrue:
2207 result = True(isolate);
2208 break;
2209 case kSerializationTagFalse:
2210 result = False(isolate);
2211 break;
2212 case kSerializationTagNumber:
2213 result = Number::New(isolate, data.Read<double>(offset));
2214 break;
2215 case kSerializationTagString: {
2216 int length = data.Read<int>(offset);
2217 CHECK(length >= 0);
2218 std::vector<char> buffer(length + 1); // + 1 so it is never empty.
2219 data.ReadMemory(&buffer[0], length, offset);
2220 MaybeLocal<String> str =
2221 String::NewFromUtf8(isolate, &buffer[0], NewStringType::kNormal,
2222 length).ToLocalChecked();
2223 if (!str.IsEmpty()) result = str.ToLocalChecked();
2224 break;
2225 }
2226 case kSerializationTagArray: {
2227 uint32_t length = data.Read<uint32_t>(offset);
2228 Local<Array> array = Array::New(isolate, length);
2229 for (uint32_t i = 0; i < length; ++i) {
2230 Local<Value> element_value;
2231 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&element_value));
2232 array->Set(isolate->GetCurrentContext(), i, element_value).FromJust();
2233 }
2234 result = array;
2235 break;
2236 }
2237 case kSerializationTagObject: {
2238 int length = data.Read<int>(offset);
2239 Local<Object> object = Object::New(isolate);
2240 for (int i = 0; i < length; ++i) {
2241 Local<Value> property_name;
2242 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_name));
2243 Local<Value> property_value;
2244 CHECK(DeserializeValue(isolate, data, offset).ToLocal(&property_value));
2245 object->Set(isolate->GetCurrentContext(), property_name, property_value)
2246 .FromJust();
2247 }
2248 result = object;
2249 break;
2250 }
2251 case kSerializationTagArrayBuffer: {
2252 int32_t byte_length = data.Read<int32_t>(offset);
2253 Local<ArrayBuffer> array_buffer = ArrayBuffer::New(isolate, byte_length);
2254 ArrayBuffer::Contents contents = array_buffer->GetContents();
2255 DCHECK(static_cast<size_t>(byte_length) == contents.ByteLength());
2256 data.ReadMemory(contents.Data(), byte_length, offset);
2257 result = array_buffer;
2258 break;
2259 }
2260 case kSerializationTagTransferredArrayBuffer: {
2261 ArrayBuffer::Contents contents;
2262 data.ReadArrayBufferContents(&contents, offset);
2263 result = ArrayBuffer::New(isolate, contents.Data(), contents.ByteLength(),
2264 ArrayBufferCreationMode::kInternalized);
2265 break;
2266 }
2267 case kSerializationTagTransferredSharedArrayBuffer: {
2268 SharedArrayBuffer::Contents contents;
2269 data.ReadSharedArrayBufferContents(&contents, offset);
2270 result = SharedArrayBuffer::New(isolate, contents.Data(),
2271 contents.ByteLength());
2272 break;
2273 }
2274 default:
2275 UNREACHABLE();
2276 }
2277
2278 return scope.Escape(result);
2279}
2280
2281
2282void Shell::CleanupWorkers() {
2283 // Make a copy of workers_, because we don't want to call Worker::Terminate
2284 // while holding the workers_mutex_ lock. Otherwise, if a worker is about to
2285 // create a new Worker, it would deadlock.
2286 i::List<Worker*> workers_copy;
2287 {
2288 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2289 allow_new_workers_ = false;
2290 workers_copy.AddAll(workers_);
2291 workers_.Clear();
2292 }
2293
2294 for (int i = 0; i < workers_copy.length(); ++i) {
2295 Worker* worker = workers_copy[i];
2296 worker->WaitForThread();
2297 delete worker;
2298 }
2299
2300 // Now that all workers are terminated, we can re-enable Worker creation.
2301 base::LockGuard<base::Mutex> lock_guard(workers_mutex_.Pointer());
2302 allow_new_workers_ = true;
2303
2304 for (int i = 0; i < externalized_shared_contents_.length(); ++i) {
2305 const SharedArrayBuffer::Contents& contents =
2306 externalized_shared_contents_[i];
2307 Shell::array_buffer_allocator->Free(contents.Data(), contents.ByteLength());
2308 }
2309 externalized_shared_contents_.Clear();
2310}
2311
2312
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002313static void DumpHeapConstants(i::Isolate* isolate) {
2314 i::Heap* heap = isolate->heap();
2315
2316 // Dump the INSTANCE_TYPES table to the console.
2317 printf("# List of known V8 instance types.\n");
2318#define DUMP_TYPE(T) printf(" %d: \"%s\",\n", i::T, #T);
2319 printf("INSTANCE_TYPES = {\n");
2320 INSTANCE_TYPE_LIST(DUMP_TYPE)
2321 printf("}\n");
2322#undef DUMP_TYPE
2323
2324 // Dump the KNOWN_MAP table to the console.
2325 printf("\n# List of known V8 maps.\n");
2326#define ROOT_LIST_CASE(type, name, camel_name) \
2327 if (n == NULL && o == heap->name()) n = #camel_name;
2328#define STRUCT_LIST_CASE(upper_name, camel_name, name) \
2329 if (n == NULL && o == heap->name##_map()) n = #camel_name "Map";
2330 i::HeapObjectIterator it(heap->map_space());
2331 printf("KNOWN_MAPS = {\n");
2332 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2333 i::Map* m = i::Map::cast(o);
2334 const char* n = NULL;
2335 intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
2336 int t = m->instance_type();
2337 ROOT_LIST(ROOT_LIST_CASE)
2338 STRUCT_LIST(STRUCT_LIST_CASE)
2339 if (n == NULL) continue;
2340 printf(" 0x%05" V8PRIxPTR ": (%d, \"%s\"),\n", p, t, n);
2341 }
2342 printf("}\n");
2343#undef STRUCT_LIST_CASE
2344#undef ROOT_LIST_CASE
2345
2346 // Dump the KNOWN_OBJECTS table to the console.
2347 printf("\n# List of known V8 objects.\n");
2348#define ROOT_LIST_CASE(type, name, camel_name) \
2349 if (n == NULL && o == heap->name()) n = #camel_name;
2350 i::OldSpaces spit(heap);
2351 printf("KNOWN_OBJECTS = {\n");
2352 for (i::PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
2353 i::HeapObjectIterator it(s);
2354 const char* sname = AllocationSpaceName(s->identity());
2355 for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
2356 const char* n = NULL;
2357 intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
2358 ROOT_LIST(ROOT_LIST_CASE)
2359 if (n == NULL) continue;
2360 printf(" (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", sname, p, n);
2361 }
2362 }
2363 printf("}\n");
2364#undef ROOT_LIST_CASE
2365}
2366#endif // !V8_SHARED
2367
2368
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002369int Shell::Main(int argc, char* argv[]) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002370#if (defined(_WIN32) || defined(_WIN64))
2371 UINT new_flags =
2372 SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
2373 UINT existing_flags = SetErrorMode(new_flags);
2374 SetErrorMode(existing_flags | new_flags);
2375#if defined(_MSC_VER)
2376 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2377 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
2378 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2379 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
2380 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
2381 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
2382 _set_error_mode(_OUT_TO_STDERR);
2383#endif // defined(_MSC_VER)
2384#endif // defined(_WIN32) || defined(_WIN64)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002385 if (!SetOptions(argc, argv)) return 1;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002386 v8::V8::InitializeICU(options.icu_data_file);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002387#ifndef V8_SHARED
2388 g_platform = i::FLAG_verify_predictable
2389 ? new PredictablePlatform()
2390 : v8::platform::CreateDefaultPlatform();
2391#else
2392 g_platform = v8::platform::CreateDefaultPlatform();
2393#endif // !V8_SHARED
2394
2395 v8::V8::InitializePlatform(g_platform);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002396 v8::V8::Initialize();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002397 if (options.natives_blob || options.snapshot_blob) {
2398 v8::V8::InitializeExternalStartupData(options.natives_blob,
2399 options.snapshot_blob);
2400 } else {
2401 v8::V8::InitializeExternalStartupData(argv[0]);
2402 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002403 SetFlagsFromString("--trace-hydrogen-file=hydrogen.cfg");
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002404 SetFlagsFromString("--trace-turbo-cfg-file=turbo.cfg");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002405 SetFlagsFromString("--redirect-code-traces-to=code.asm");
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002406 int result = 0;
2407 Isolate::CreateParams create_params;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002408 ShellArrayBufferAllocator shell_array_buffer_allocator;
2409 MockArrayBufferAllocator mock_arraybuffer_allocator;
2410 if (options.mock_arraybuffer_allocator) {
2411 Shell::array_buffer_allocator = &mock_arraybuffer_allocator;
2412 } else {
2413 Shell::array_buffer_allocator = &shell_array_buffer_allocator;
2414 }
2415 create_params.array_buffer_allocator = Shell::array_buffer_allocator;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002416#ifdef ENABLE_VTUNE_JIT_INTERFACE
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002417 create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002418#endif
2419#ifndef V8_SHARED
2420 create_params.constraints.ConfigureDefaults(
2421 base::SysInfo::AmountOfPhysicalMemory(),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002422 base::SysInfo::AmountOfVirtualMemory());
2423
2424 Shell::counter_map_ = new CounterMap();
2425 if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
2426 create_params.counter_lookup_callback = LookupCounter;
2427 create_params.create_histogram_callback = CreateHistogram;
2428 create_params.add_histogram_sample_callback = AddHistogramSample;
2429 }
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002430#endif
2431 Isolate* isolate = Isolate::New(create_params);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002432 {
2433 Isolate::Scope scope(isolate);
2434 Initialize(isolate);
2435 PerIsolateData data(isolate);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002436
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002437#ifndef V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002438 if (options.dump_heap_constants) {
2439 DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate));
2440 return 0;
2441 }
2442#endif
2443
2444 if (options.stress_opt || options.stress_deopt) {
2445 Testing::SetStressRunType(options.stress_opt
2446 ? Testing::kStressTypeOpt
2447 : Testing::kStressTypeDeopt);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002448 options.stress_runs = Testing::GetStressRuns();
2449 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2450 printf("============ Stress %d/%d ============\n", i + 1,
2451 options.stress_runs);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002452 Testing::PrepareStressRun(i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002453 bool last_run = i == options.stress_runs - 1;
2454 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002455 }
2456 printf("======== Full Deoptimization =======\n");
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002457 Testing::DeoptimizeAll(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002458#if !defined(V8_SHARED)
2459 } else if (i::FLAG_stress_runs > 0) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002460 options.stress_runs = i::FLAG_stress_runs;
2461 for (int i = 0; i < options.stress_runs && result == 0; i++) {
2462 printf("============ Run %d/%d ============\n", i + 1,
2463 options.stress_runs);
2464 bool last_run = i == options.stress_runs - 1;
2465 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002466 }
2467#endif
2468 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002469 bool last_run = true;
2470 result = RunMain(isolate, argc, argv, last_run);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002471 }
2472
2473 // Run interactive shell if explicitly requested or if no script has been
2474 // executed, but never on --test
2475 if (options.use_interactive_shell()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002476 RunShell(isolate);
2477 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002478
2479 // Shut down contexts and collect garbage.
2480 evaluation_context_.Reset();
2481#ifndef V8_SHARED
Ben Murdochda12d292016-06-02 14:46:10 +01002482 stringify_function_.Reset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002483#endif // !V8_SHARED
2484 CollectGarbage(isolate);
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002485 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -04002486 OnExit(isolate);
2487#ifndef V8_SHARED
2488 // Dump basic block profiling data.
2489 if (i::BasicBlockProfiler* profiler =
2490 reinterpret_cast<i::Isolate*>(isolate)->basic_block_profiler()) {
2491 i::OFStream os(stdout);
2492 os << *profiler;
2493 }
2494#endif // !V8_SHARED
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002495 isolate->Dispose();
2496 V8::Dispose();
2497 V8::ShutdownPlatform();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002498 delete g_platform;
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002499
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00002500 return result;
2501}
2502
Steve Blocka7e24c12009-10-30 11:49:00 +00002503} // namespace v8
2504
2505
Ben Murdoch257744e2011-11-30 15:57:28 +00002506#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +00002507int main(int argc, char* argv[]) {
2508 return v8::Shell::Main(argc, argv);
2509}
Ben Murdoch257744e2011-11-30 15:57:28 +00002510#endif