The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / d8.cc @ f230a1cf

History | View | Annotate | Download (54 KB)

1
// Copyright 2012 the V8 project authors. All rights reserved.
2
// Redistribution and use in source and binary forms, with or without
3
// modification, are permitted provided that the following conditions are
4
// met:
5
//
6
//     * Redistributions of source code must retain the above copyright
7
//       notice, this list of conditions and the following disclaimer.
8
//     * Redistributions in binary form must reproduce the above
9
//       copyright notice, this list of conditions and the following
10
//       disclaimer in the documentation and/or other materials provided
11
//       with the distribution.
12
//     * Neither the name of Google Inc. nor the names of its
13
//       contributors may be used to endorse or promote products derived
14
//       from this software without specific prior written permission.
15
//
16
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27

    
28

    
29
// Defined when linking against shared lib on Windows.
30
#if defined(USING_V8_SHARED) && !defined(V8_SHARED)
31
#define V8_SHARED
32
#endif
33

    
34
#ifdef COMPRESS_STARTUP_DATA_BZ2
35
#include <bzlib.h>
36
#endif
37

    
38
#include <errno.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <sys/stat.h>
42

    
43
#ifdef V8_SHARED
44
#include <assert.h>
45
#endif  // V8_SHARED
46

    
47
#ifndef V8_SHARED
48
#include <algorithm>
49
#endif  // !V8_SHARED
50

    
51
#ifdef V8_SHARED
52
#include "../include/v8-defaults.h"
53
#include "../include/v8-testing.h"
54
#endif  // V8_SHARED
55

    
56
#ifdef ENABLE_VTUNE_JIT_INTERFACE
57
#include "third_party/vtune/v8-vtune.h"
58
#endif
59

    
60
#include "d8.h"
61

    
62
#ifndef V8_SHARED
63
#include "api.h"
64
#include "checks.h"
65
#include "d8-debug.h"
66
#include "debug.h"
67
#include "natives.h"
68
#include "platform.h"
69
#include "v8.h"
70
#include "v8-defaults.h"
71
#endif  // V8_SHARED
72

    
73
#if !defined(_WIN32) && !defined(_WIN64)
74
#include <unistd.h>  // NOLINT
75
#endif
76

    
77
#ifndef ASSERT
78
#define ASSERT(condition) assert(condition)
79
#endif
80

    
81
namespace v8 {
82

    
83

    
84
static Handle<Value> Throw(const char* message) {
85
  return ThrowException(String::New(message));
86
}
87

    
88

    
89

    
90
class PerIsolateData {
91
 public:
92
  explicit PerIsolateData(Isolate* isolate) : isolate_(isolate), realms_(NULL) {
93
    HandleScope scope(isolate);
94
    isolate->SetData(this);
95
  }
96

    
97
  ~PerIsolateData() {
98
    isolate_->SetData(NULL);  // Not really needed, just to be sure...
99
  }
100

    
101
  inline static PerIsolateData* Get(Isolate* isolate) {
102
    return reinterpret_cast<PerIsolateData*>(isolate->GetData());
103
  }
104

    
105
  class RealmScope {
106
   public:
107
    explicit RealmScope(PerIsolateData* data);
108
    ~RealmScope();
109
   private:
110
    PerIsolateData* data_;
111
  };
112

    
113
 private:
114
  friend class Shell;
115
  friend class RealmScope;
116
  Isolate* isolate_;
117
  int realm_count_;
118
  int realm_current_;
119
  int realm_switch_;
120
  Persistent<Context>* realms_;
121
  Persistent<Value> realm_shared_;
122

    
123
  int RealmFind(Handle<Context> context);
124
};
125

    
126

    
127
LineEditor *LineEditor::current_ = NULL;
128

    
129

    
130
LineEditor::LineEditor(Type type, const char* name)
131
    : type_(type), name_(name) {
132
  if (current_ == NULL || current_->type_ < type) current_ = this;
133
}
134

    
135

    
136
class DumbLineEditor: public LineEditor {
137
 public:
138
  explicit DumbLineEditor(Isolate* isolate)
139
      : LineEditor(LineEditor::DUMB, "dumb"), isolate_(isolate) { }
140
  virtual Handle<String> Prompt(const char* prompt);
141
 private:
142
  Isolate* isolate_;
143
};
144

    
145

    
146
Handle<String> DumbLineEditor::Prompt(const char* prompt) {
147
  printf("%s", prompt);
148
#if defined(__native_client__)
149
  // Native Client libc is used to being embedded in Chrome and
150
  // has trouble recognizing when to flush.
151
  fflush(stdout);
152
#endif
153
  return Shell::ReadFromStdin(isolate_);
154
}
155

    
156

    
157
#ifndef V8_SHARED
158
CounterMap* Shell::counter_map_;
159
i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
160
CounterCollection Shell::local_counters_;
161
CounterCollection* Shell::counters_ = &local_counters_;
162
i::Mutex Shell::context_mutex_;
163
const i::TimeTicks Shell::kInitialTicks = i::TimeTicks::HighResolutionNow();
164
Persistent<Context> Shell::utility_context_;
165
#endif  // V8_SHARED
166

    
167
Persistent<Context> Shell::evaluation_context_;
168
ShellOptions Shell::options;
169
const char* Shell::kPrompt = "d8> ";
170

    
171

    
172
const int MB = 1024 * 1024;
173

    
174

    
175
#ifndef V8_SHARED
176
bool CounterMap::Match(void* key1, void* key2) {
177
  const char* name1 = reinterpret_cast<const char*>(key1);
178
  const char* name2 = reinterpret_cast<const char*>(key2);
179
  return strcmp(name1, name2) == 0;
180
}
181
#endif  // V8_SHARED
182

    
183

    
184
// Converts a V8 value to a C string.
185
const char* Shell::ToCString(const v8::String::Utf8Value& value) {
186
  return *value ? *value : "<string conversion failed>";
187
}
188

    
189

    
190
// Executes a string within the current v8 context.
191
bool Shell::ExecuteString(Isolate* isolate,
192
                          Handle<String> source,
193
                          Handle<Value> name,
194
                          bool print_result,
195
                          bool report_exceptions) {
196
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
197
  bool FLAG_debugger = i::FLAG_debugger;
198
#else
199
  bool FLAG_debugger = false;
200
#endif  // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
201
  HandleScope handle_scope(isolate);
202
  TryCatch try_catch;
203
  options.script_executed = true;
204
  if (FLAG_debugger) {
205
    // When debugging make exceptions appear to be uncaught.
206
    try_catch.SetVerbose(true);
207
  }
208
  Handle<Script> script = Script::New(source, name);
209
  if (script.IsEmpty()) {
210
    // Print errors that happened during compilation.
211
    if (report_exceptions && !FLAG_debugger)
212
      ReportException(isolate, &try_catch);
213
    return false;
214
  } else {
215
    PerIsolateData* data = PerIsolateData::Get(isolate);
216
    Local<Context> realm =
217
        Local<Context>::New(isolate, data->realms_[data->realm_current_]);
218
    realm->Enter();
219
    Handle<Value> result = script->Run();
220
    realm->Exit();
221
    data->realm_current_ = data->realm_switch_;
222
    if (result.IsEmpty()) {
223
      ASSERT(try_catch.HasCaught());
224
      // Print errors that happened during execution.
225
      if (report_exceptions && !FLAG_debugger)
226
        ReportException(isolate, &try_catch);
227
      return false;
228
    } else {
229
      ASSERT(!try_catch.HasCaught());
230
      if (print_result) {
231
#if !defined(V8_SHARED)
232
        if (options.test_shell) {
233
#endif
234
          if (!result->IsUndefined()) {
235
            // If all went well and the result wasn't undefined then print
236
            // the returned value.
237
            v8::String::Utf8Value str(result);
238
            fwrite(*str, sizeof(**str), str.length(), stdout);
239
            printf("\n");
240
          }
241
#if !defined(V8_SHARED)
242
        } else {
243
          v8::TryCatch try_catch;
244
          v8::Local<v8::Context> context =
245
              v8::Local<v8::Context>::New(isolate, utility_context_);
246
          v8::Context::Scope context_scope(context);
247
          Handle<Object> global = context->Global();
248
          Handle<Value> fun = global->Get(String::New("Stringify"));
249
          Handle<Value> argv[1] = { result };
250
          Handle<Value> s = Handle<Function>::Cast(fun)->Call(global, 1, argv);
251
          if (try_catch.HasCaught()) return true;
252
          v8::String::Utf8Value str(s);
253
          fwrite(*str, sizeof(**str), str.length(), stdout);
254
          printf("\n");
255
        }
256
#endif
257
      }
258
      return true;
259
    }
260
  }
261
}
262

    
263

    
264
PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
265
  data_->realm_count_ = 1;
266
  data_->realm_current_ = 0;
267
  data_->realm_switch_ = 0;
268
  data_->realms_ = new Persistent<Context>[1];
269
  data_->realms_[0].Reset(data_->isolate_,
270
                          data_->isolate_->GetEnteredContext());
271
  data_->realm_shared_.Clear();
272
}
273

    
274

    
275
PerIsolateData::RealmScope::~RealmScope() {
276
  // Drop realms to avoid keeping them alive.
277
  for (int i = 0; i < data_->realm_count_; ++i)
278
    data_->realms_[i].Dispose();
279
  delete[] data_->realms_;
280
  if (!data_->realm_shared_.IsEmpty())
281
    data_->realm_shared_.Dispose();
282
}
283

    
284

    
285
int PerIsolateData::RealmFind(Handle<Context> context) {
286
  for (int i = 0; i < realm_count_; ++i) {
287
    if (realms_[i] == context) return i;
288
  }
289
  return -1;
290
}
291

    
292

    
293
#ifndef V8_SHARED
294
// performance.now() returns a time stamp as double, measured in milliseconds.
295
void Shell::PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args) {
296
  i::TimeDelta delta = i::TimeTicks::HighResolutionNow() - kInitialTicks;
297
  args.GetReturnValue().Set(delta.InMillisecondsF());
298
}
299
#endif  // V8_SHARED
300

    
301

    
302
// Realm.current() returns the index of the currently active realm.
303
void Shell::RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args) {
304
  Isolate* isolate = args.GetIsolate();
305
  PerIsolateData* data = PerIsolateData::Get(isolate);
306
  int index = data->RealmFind(isolate->GetEnteredContext());
307
  if (index == -1) return;
308
  args.GetReturnValue().Set(index);
309
}
310

    
311

    
312
// Realm.owner(o) returns the index of the realm that created o.
313
void Shell::RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args) {
314
  Isolate* isolate = args.GetIsolate();
315
  PerIsolateData* data = PerIsolateData::Get(isolate);
316
  if (args.Length() < 1 || !args[0]->IsObject()) {
317
    Throw("Invalid argument");
318
    return;
319
  }
320
  int index = data->RealmFind(args[0]->ToObject()->CreationContext());
321
  if (index == -1) return;
322
  args.GetReturnValue().Set(index);
323
}
324

    
325

    
326
// Realm.global(i) returns the global object of realm i.
327
// (Note that properties of global objects cannot be read/written cross-realm.)
328
void Shell::RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args) {
329
  PerIsolateData* data = PerIsolateData::Get(args.GetIsolate());
330
  if (args.Length() < 1 || !args[0]->IsNumber()) {
331
    Throw("Invalid argument");
332
    return;
333
  }
334
  int index = args[0]->Uint32Value();
335
  if (index >= data->realm_count_ || data->realms_[index].IsEmpty()) {
336
    Throw("Invalid realm index");
337
    return;
338
  }
339
  args.GetReturnValue().Set(
340
      Local<Context>::New(args.GetIsolate(), data->realms_[index])->Global());
341
}
342

    
343

    
344
// Realm.create() creates a new realm and returns its index.
345
void Shell::RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args) {
346
  Isolate* isolate = args.GetIsolate();
347
  PerIsolateData* data = PerIsolateData::Get(isolate);
348
  Persistent<Context>* old_realms = data->realms_;
349
  int index = data->realm_count_;
350
  data->realms_ = new Persistent<Context>[++data->realm_count_];
351
  for (int i = 0; i < index; ++i) {
352
    data->realms_[i].Reset(isolate, old_realms[i]);
353
  }
354
  delete[] old_realms;
355
  Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
356
  data->realms_[index].Reset(
357
      isolate, Context::New(isolate, NULL, global_template));
358
  args.GetReturnValue().Set(index);
359
}
360

    
361

    
362
// Realm.dispose(i) disposes the reference to the realm i.
363
void Shell::RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args) {
364
  Isolate* isolate = args.GetIsolate();
365
  PerIsolateData* data = PerIsolateData::Get(isolate);
366
  if (args.Length() < 1 || !args[0]->IsNumber()) {
367
    Throw("Invalid argument");
368
    return;
369
  }
370
  int index = args[0]->Uint32Value();
371
  if (index >= data->realm_count_ || data->realms_[index].IsEmpty() ||
372
      index == 0 ||
373
      index == data->realm_current_ || index == data->realm_switch_) {
374
    Throw("Invalid realm index");
375
    return;
376
  }
377
  data->realms_[index].Dispose();
378
  data->realms_[index].Clear();
379
}
380

    
381

    
382
// Realm.switch(i) switches to the realm i for consecutive interactive inputs.
383
void Shell::RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args) {
384
  Isolate* isolate = args.GetIsolate();
385
  PerIsolateData* data = PerIsolateData::Get(isolate);
386
  if (args.Length() < 1 || !args[0]->IsNumber()) {
387
    Throw("Invalid argument");
388
    return;
389
  }
390
  int index = args[0]->Uint32Value();
391
  if (index >= data->realm_count_ || data->realms_[index].IsEmpty()) {
392
    Throw("Invalid realm index");
393
    return;
394
  }
395
  data->realm_switch_ = index;
396
}
397

    
398

    
399
// Realm.eval(i, s) evaluates s in realm i and returns the result.
400
void Shell::RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args) {
401
  Isolate* isolate = args.GetIsolate();
402
  PerIsolateData* data = PerIsolateData::Get(isolate);
403
  if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsString()) {
404
    Throw("Invalid argument");
405
    return;
406
  }
407
  int index = args[0]->Uint32Value();
408
  if (index >= data->realm_count_ || data->realms_[index].IsEmpty()) {
409
    Throw("Invalid realm index");
410
    return;
411
  }
412
  Handle<Script> script = Script::New(args[1]->ToString());
413
  if (script.IsEmpty()) return;
414
  Local<Context> realm = Local<Context>::New(isolate, data->realms_[index]);
415
  realm->Enter();
416
  Handle<Value> result = script->Run();
417
  realm->Exit();
418
  args.GetReturnValue().Set(result);
419
}
420

    
421

    
422
// Realm.shared is an accessor for a single shared value across realms.
423
void Shell::RealmSharedGet(Local<String> property,
424
                           const PropertyCallbackInfo<Value>& info) {
425
  Isolate* isolate = info.GetIsolate();
426
  PerIsolateData* data = PerIsolateData::Get(isolate);
427
  if (data->realm_shared_.IsEmpty()) return;
428
  info.GetReturnValue().Set(data->realm_shared_);
429
}
430

    
431
void Shell::RealmSharedSet(Local<String> property,
432
                           Local<Value> value,
433
                           const PropertyCallbackInfo<void>& info) {
434
  Isolate* isolate = info.GetIsolate();
435
  PerIsolateData* data = PerIsolateData::Get(isolate);
436
  if (!data->realm_shared_.IsEmpty()) data->realm_shared_.Dispose();
437
  data->realm_shared_.Reset(isolate, value);
438
}
439

    
440

    
441
void Shell::Print(const v8::FunctionCallbackInfo<v8::Value>& args) {
442
  Write(args);
443
  printf("\n");
444
  fflush(stdout);
445
}
446

    
447

    
448
void Shell::Write(const v8::FunctionCallbackInfo<v8::Value>& args) {
449
  for (int i = 0; i < args.Length(); i++) {
450
    HandleScope handle_scope(args.GetIsolate());
451
    if (i != 0) {
452
      printf(" ");
453
    }
454

    
455
    // Explicitly catch potential exceptions in toString().
456
    v8::TryCatch try_catch;
457
    Handle<String> str_obj = args[i]->ToString();
458
    if (try_catch.HasCaught()) {
459
      try_catch.ReThrow();
460
      return;
461
    }
462

    
463
    v8::String::Utf8Value str(str_obj);
464
    int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
465
    if (n != str.length()) {
466
      printf("Error in fwrite\n");
467
      Exit(1);
468
    }
469
  }
470
}
471

    
472

    
473
void Shell::Read(const v8::FunctionCallbackInfo<v8::Value>& args) {
474
  String::Utf8Value file(args[0]);
475
  if (*file == NULL) {
476
    Throw("Error loading file");
477
    return;
478
  }
479
  Handle<String> source = ReadFile(args.GetIsolate(), *file);
480
  if (source.IsEmpty()) {
481
    Throw("Error loading file");
482
    return;
483
  }
484
  args.GetReturnValue().Set(source);
485
}
486

    
487

    
488
Handle<String> Shell::ReadFromStdin(Isolate* isolate) {
489
  static const int kBufferSize = 256;
490
  char buffer[kBufferSize];
491
  Handle<String> accumulator = String::New("");
492
  int length;
493
  while (true) {
494
    // Continue reading if the line ends with an escape '\\' or the line has
495
    // not been fully read into the buffer yet (does not end with '\n').
496
    // If fgets gets an error, just give up.
497
    char* input = NULL;
498
    {  // Release lock for blocking input.
499
      Unlocker unlock(isolate);
500
      input = fgets(buffer, kBufferSize, stdin);
501
    }
502
    if (input == NULL) return Handle<String>();
503
    length = static_cast<int>(strlen(buffer));
504
    if (length == 0) {
505
      return accumulator;
506
    } else if (buffer[length-1] != '\n') {
507
      accumulator = String::Concat(accumulator, String::New(buffer, length));
508
    } else if (length > 1 && buffer[length-2] == '\\') {
509
      buffer[length-2] = '\n';
510
      accumulator = String::Concat(accumulator, String::New(buffer, length-1));
511
    } else {
512
      return String::Concat(accumulator, String::New(buffer, length-1));
513
    }
514
  }
515
}
516

    
517

    
518
void Shell::Load(const v8::FunctionCallbackInfo<v8::Value>& args) {
519
  for (int i = 0; i < args.Length(); i++) {
520
    HandleScope handle_scope(args.GetIsolate());
521
    String::Utf8Value file(args[i]);
522
    if (*file == NULL) {
523
      Throw("Error loading file");
524
      return;
525
    }
526
    Handle<String> source = ReadFile(args.GetIsolate(), *file);
527
    if (source.IsEmpty()) {
528
      Throw("Error loading file");
529
      return;
530
    }
531
    if (!ExecuteString(args.GetIsolate(),
532
                       source,
533
                       String::New(*file),
534
                       false,
535
                       true)) {
536
      Throw("Error executing file");
537
      return;
538
    }
539
  }
540
}
541

    
542

    
543
void Shell::Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
544
  int exit_code = args[0]->Int32Value();
545
  OnExit();
546
  exit(exit_code);
547
}
548

    
549

    
550
void Shell::Version(const v8::FunctionCallbackInfo<v8::Value>& args) {
551
  args.GetReturnValue().Set(String::New(V8::GetVersion()));
552
}
553

    
554

    
555
void Shell::ReportException(Isolate* isolate, v8::TryCatch* try_catch) {
556
  HandleScope handle_scope(isolate);
557
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
558
  Handle<Context> utility_context;
559
  bool enter_context = !Context::InContext();
560
  if (enter_context) {
561
    utility_context = Local<Context>::New(isolate, utility_context_);
562
    utility_context->Enter();
563
  }
564
#endif  // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
565
  v8::String::Utf8Value exception(try_catch->Exception());
566
  const char* exception_string = ToCString(exception);
567
  Handle<Message> message = try_catch->Message();
568
  if (message.IsEmpty()) {
569
    // V8 didn't provide any extra information about this error; just
570
    // print the exception.
571
    printf("%s\n", exception_string);
572
  } else {
573
    // Print (filename):(line number): (message).
574
    v8::String::Utf8Value filename(message->GetScriptResourceName());
575
    const char* filename_string = ToCString(filename);
576
    int linenum = message->GetLineNumber();
577
    printf("%s:%i: %s\n", filename_string, linenum, exception_string);
578
    // Print line of source code.
579
    v8::String::Utf8Value sourceline(message->GetSourceLine());
580
    const char* sourceline_string = ToCString(sourceline);
581
    printf("%s\n", sourceline_string);
582
    // Print wavy underline (GetUnderline is deprecated).
583
    int start = message->GetStartColumn();
584
    for (int i = 0; i < start; i++) {
585
      printf(" ");
586
    }
587
    int end = message->GetEndColumn();
588
    for (int i = start; i < end; i++) {
589
      printf("^");
590
    }
591
    printf("\n");
592
    v8::String::Utf8Value stack_trace(try_catch->StackTrace());
593
    if (stack_trace.length() > 0) {
594
      const char* stack_trace_string = ToCString(stack_trace);
595
      printf("%s\n", stack_trace_string);
596
    }
597
  }
598
  printf("\n");
599
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
600
  if (enter_context) utility_context->Exit();
601
#endif  // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
602
}
603

    
604

    
605
#ifndef V8_SHARED
606
Handle<Array> Shell::GetCompletions(Isolate* isolate,
607
                                    Handle<String> text,
608
                                    Handle<String> full) {
609
  HandleScope handle_scope(isolate);
610
  v8::Local<v8::Context> utility_context =
611
      v8::Local<v8::Context>::New(isolate, utility_context_);
612
  v8::Context::Scope context_scope(utility_context);
613
  Handle<Object> global = utility_context->Global();
614
  Handle<Value> fun = global->Get(String::New("GetCompletions"));
615
  static const int kArgc = 3;
616
  v8::Local<v8::Context> evaluation_context =
617
      v8::Local<v8::Context>::New(isolate, evaluation_context_);
618
  Handle<Value> argv[kArgc] = { evaluation_context->Global(), text, full };
619
  Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
620
  return handle_scope.Close(Handle<Array>::Cast(val));
621
}
622

    
623

    
624
#ifdef ENABLE_DEBUGGER_SUPPORT
625
Handle<Object> Shell::DebugMessageDetails(Isolate* isolate,
626
                                          Handle<String> message) {
627
  HandleScope handle_scope(isolate);
628
  v8::Local<v8::Context> context =
629
      v8::Local<v8::Context>::New(isolate, utility_context_);
630
  v8::Context::Scope context_scope(context);
631
  Handle<Object> global = context->Global();
632
  Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
633
  static const int kArgc = 1;
634
  Handle<Value> argv[kArgc] = { message };
635
  Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
636
  return Handle<Object>::Cast(val);
637
}
638

    
639

    
640
Handle<Value> Shell::DebugCommandToJSONRequest(Isolate* isolate,
641
                                               Handle<String> command) {
642
  HandleScope handle_scope(isolate);
643
  v8::Local<v8::Context> context =
644
      v8::Local<v8::Context>::New(isolate, utility_context_);
645
  v8::Context::Scope context_scope(context);
646
  Handle<Object> global = context->Global();
647
  Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
648
  static const int kArgc = 1;
649
  Handle<Value> argv[kArgc] = { command };
650
  Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
651
  return val;
652
}
653

    
654

    
655
void Shell::DispatchDebugMessages() {
656
  Isolate* isolate = v8::Isolate::GetCurrent();
657
  HandleScope handle_scope(isolate);
658
  v8::Local<v8::Context> context =
659
      v8::Local<v8::Context>::New(isolate, Shell::evaluation_context_);
660
  v8::Context::Scope context_scope(context);
661
  v8::Debug::ProcessDebugMessages();
662
}
663
#endif  // ENABLE_DEBUGGER_SUPPORT
664
#endif  // V8_SHARED
665

    
666

    
667
#ifndef V8_SHARED
668
int32_t* Counter::Bind(const char* name, bool is_histogram) {
669
  int i;
670
  for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
671
    name_[i] = static_cast<char>(name[i]);
672
  name_[i] = '\0';
673
  is_histogram_ = is_histogram;
674
  return ptr();
675
}
676

    
677

    
678
void Counter::AddSample(int32_t sample) {
679
  count_++;
680
  sample_total_ += sample;
681
}
682

    
683

    
684
CounterCollection::CounterCollection() {
685
  magic_number_ = 0xDEADFACE;
686
  max_counters_ = kMaxCounters;
687
  max_name_size_ = Counter::kMaxNameSize;
688
  counters_in_use_ = 0;
689
}
690

    
691

    
692
Counter* CounterCollection::GetNextCounter() {
693
  if (counters_in_use_ == kMaxCounters) return NULL;
694
  return &counters_[counters_in_use_++];
695
}
696

    
697

    
698
void Shell::MapCounters(const char* name) {
699
  counters_file_ = i::OS::MemoryMappedFile::create(
700
      name, sizeof(CounterCollection), &local_counters_);
701
  void* memory = (counters_file_ == NULL) ?
702
      NULL : counters_file_->memory();
703
  if (memory == NULL) {
704
    printf("Could not map counters file %s\n", name);
705
    Exit(1);
706
  }
707
  counters_ = static_cast<CounterCollection*>(memory);
708
  V8::SetCounterFunction(LookupCounter);
709
  V8::SetCreateHistogramFunction(CreateHistogram);
710
  V8::SetAddHistogramSampleFunction(AddHistogramSample);
711
}
712

    
713

    
714
int CounterMap::Hash(const char* name) {
715
  int h = 0;
716
  int c;
717
  while ((c = *name++) != 0) {
718
    h += h << 5;
719
    h += c;
720
  }
721
  return h;
722
}
723

    
724

    
725
Counter* Shell::GetCounter(const char* name, bool is_histogram) {
726
  Counter* counter = counter_map_->Lookup(name);
727

    
728
  if (counter == NULL) {
729
    counter = counters_->GetNextCounter();
730
    if (counter != NULL) {
731
      counter_map_->Set(name, counter);
732
      counter->Bind(name, is_histogram);
733
    }
734
  } else {
735
    ASSERT(counter->is_histogram() == is_histogram);
736
  }
737
  return counter;
738
}
739

    
740

    
741
int* Shell::LookupCounter(const char* name) {
742
  Counter* counter = GetCounter(name, false);
743

    
744
  if (counter != NULL) {
745
    return counter->ptr();
746
  } else {
747
    return NULL;
748
  }
749
}
750

    
751

    
752
void* Shell::CreateHistogram(const char* name,
753
                             int min,
754
                             int max,
755
                             size_t buckets) {
756
  return GetCounter(name, true);
757
}
758

    
759

    
760
void Shell::AddHistogramSample(void* histogram, int sample) {
761
  Counter* counter = reinterpret_cast<Counter*>(histogram);
762
  counter->AddSample(sample);
763
}
764

    
765

    
766
void Shell::InstallUtilityScript(Isolate* isolate) {
767
  Locker lock(isolate);
768
  HandleScope scope(isolate);
769
  // If we use the utility context, we have to set the security tokens so that
770
  // utility, evaluation and debug context can all access each other.
771
  v8::Local<v8::Context> utility_context =
772
      v8::Local<v8::Context>::New(isolate, utility_context_);
773
  v8::Local<v8::Context> evaluation_context =
774
      v8::Local<v8::Context>::New(isolate, evaluation_context_);
775
  utility_context->SetSecurityToken(Undefined(isolate));
776
  evaluation_context->SetSecurityToken(Undefined(isolate));
777
  v8::Context::Scope context_scope(utility_context);
778

    
779
#ifdef ENABLE_DEBUGGER_SUPPORT
780
  if (i::FLAG_debugger) printf("JavaScript debugger enabled\n");
781
  // Install the debugger object in the utility scope
782
  i::Debug* debug = reinterpret_cast<i::Isolate*>(isolate)->debug();
783
  debug->Load();
784
  i::Handle<i::JSObject> js_debug
785
      = i::Handle<i::JSObject>(debug->debug_context()->global_object());
786
  utility_context->Global()->Set(String::New("$debug"),
787
                                  Utils::ToLocal(js_debug));
788
  debug->debug_context()->set_security_token(
789
      reinterpret_cast<i::Isolate*>(isolate)->heap()->undefined_value());
790
#endif  // ENABLE_DEBUGGER_SUPPORT
791

    
792
  // Run the d8 shell utility script in the utility context
793
  int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
794
  i::Vector<const char> shell_source =
795
      i::NativesCollection<i::D8>::GetRawScriptSource(source_index);
796
  i::Vector<const char> shell_source_name =
797
      i::NativesCollection<i::D8>::GetScriptName(source_index);
798
  Handle<String> source = String::New(shell_source.start(),
799
      shell_source.length());
800
  Handle<String> name = String::New(shell_source_name.start(),
801
      shell_source_name.length());
802
  Handle<Script> script = Script::Compile(source, name);
803
  script->Run();
804
  // Mark the d8 shell script as native to avoid it showing up as normal source
805
  // in the debugger.
806
  i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
807
  i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
808
      ? i::Handle<i::Script>(i::Script::cast(
809
          i::JSFunction::cast(*compiled_script)->shared()->script()))
810
      : i::Handle<i::Script>(i::Script::cast(
811
          i::SharedFunctionInfo::cast(*compiled_script)->script()));
812
  script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
813

    
814
#ifdef ENABLE_DEBUGGER_SUPPORT
815
  // Start the in-process debugger if requested.
816
  if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
817
    v8::Debug::SetDebugEventListener2(HandleDebugEvent);
818
  }
819
#endif  // ENABLE_DEBUGGER_SUPPORT
820
}
821
#endif  // V8_SHARED
822

    
823

    
824
#ifdef COMPRESS_STARTUP_DATA_BZ2
825
class BZip2Decompressor : public v8::StartupDataDecompressor {
826
 public:
827
  virtual ~BZip2Decompressor() { }
828

    
829
 protected:
830
  virtual int DecompressData(char* raw_data,
831
                             int* raw_data_size,
832
                             const char* compressed_data,
833
                             int compressed_data_size) {
834
    ASSERT_EQ(v8::StartupData::kBZip2,
835
              v8::V8::GetCompressedStartupDataAlgorithm());
836
    unsigned int decompressed_size = *raw_data_size;
837
    int result =
838
        BZ2_bzBuffToBuffDecompress(raw_data,
839
                                   &decompressed_size,
840
                                   const_cast<char*>(compressed_data),
841
                                   compressed_data_size,
842
                                   0, 1);
843
    if (result == BZ_OK) {
844
      *raw_data_size = decompressed_size;
845
    }
846
    return result;
847
  }
848
};
849
#endif
850

    
851

    
852
Handle<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
853
  Handle<ObjectTemplate> global_template = ObjectTemplate::New();
854
  global_template->Set(String::New("print"), FunctionTemplate::New(Print));
855
  global_template->Set(String::New("write"), FunctionTemplate::New(Write));
856
  global_template->Set(String::New("read"), FunctionTemplate::New(Read));
857
  global_template->Set(String::New("readbuffer"),
858
                       FunctionTemplate::New(ReadBuffer));
859
  global_template->Set(String::New("readline"),
860
                       FunctionTemplate::New(ReadLine));
861
  global_template->Set(String::New("load"), FunctionTemplate::New(Load));
862
  global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
863
  global_template->Set(String::New("version"), FunctionTemplate::New(Version));
864

    
865
  // Bind the Realm object.
866
  Handle<ObjectTemplate> realm_template = ObjectTemplate::New();
867
  realm_template->Set(String::New("current"),
868
                      FunctionTemplate::New(RealmCurrent));
869
  realm_template->Set(String::New("owner"),
870
                      FunctionTemplate::New(RealmOwner));
871
  realm_template->Set(String::New("global"),
872
                      FunctionTemplate::New(RealmGlobal));
873
  realm_template->Set(String::New("create"),
874
                      FunctionTemplate::New(RealmCreate));
875
  realm_template->Set(String::New("dispose"),
876
                      FunctionTemplate::New(RealmDispose));
877
  realm_template->Set(String::New("switch"),
878
                      FunctionTemplate::New(RealmSwitch));
879
  realm_template->Set(String::New("eval"),
880
                      FunctionTemplate::New(RealmEval));
881
  realm_template->SetAccessor(String::New("shared"),
882
                              RealmSharedGet, RealmSharedSet);
883
  global_template->Set(String::New("Realm"), realm_template);
884

    
885
#ifndef V8_SHARED
886
  Handle<ObjectTemplate> performance_template = ObjectTemplate::New();
887
  performance_template->Set(String::New("now"),
888
                            FunctionTemplate::New(PerformanceNow));
889
  global_template->Set(String::New("performance"), performance_template);
890
#endif  // V8_SHARED
891

    
892
#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
893
  Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
894
  AddOSMethods(os_templ);
895
  global_template->Set(String::New("os"), os_templ);
896
#endif  // V8_SHARED
897

    
898
  return global_template;
899
}
900

    
901

    
902
void Shell::Initialize(Isolate* isolate) {
903
#ifdef COMPRESS_STARTUP_DATA_BZ2
904
  BZip2Decompressor startup_data_decompressor;
905
  int bz2_result = startup_data_decompressor.Decompress();
906
  if (bz2_result != BZ_OK) {
907
    fprintf(stderr, "bzip error code: %d\n", bz2_result);
908
    Exit(1);
909
  }
910
#endif
911

    
912
#ifndef V8_SHARED
913
  Shell::counter_map_ = new CounterMap();
914
  // Set up counters
915
  if (i::StrLength(i::FLAG_map_counters) != 0)
916
    MapCounters(i::FLAG_map_counters);
917
  if (i::FLAG_dump_counters || i::FLAG_track_gc_object_stats) {
918
    V8::SetCounterFunction(LookupCounter);
919
    V8::SetCreateHistogramFunction(CreateHistogram);
920
    V8::SetAddHistogramSampleFunction(AddHistogramSample);
921
  }
922
#endif  // V8_SHARED
923
}
924

    
925

    
926
void Shell::InitializeDebugger(Isolate* isolate) {
927
  if (options.test_shell) return;
928
#ifndef V8_SHARED
929
  Locker lock(isolate);
930
  HandleScope scope(isolate);
931
  Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
932
  utility_context_.Reset(isolate,
933
                         Context::New(isolate, NULL, global_template));
934

    
935
#ifdef ENABLE_DEBUGGER_SUPPORT
936
  // Start the debugger agent if requested.
937
  if (i::FLAG_debugger_agent) {
938
    v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
939
    v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true);
940
  }
941
#endif  // ENABLE_DEBUGGER_SUPPORT
942
#endif  // V8_SHARED
943
}
944

    
945

    
946
Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) {
947
#ifndef V8_SHARED
948
  // This needs to be a critical section since this is not thread-safe
949
  i::LockGuard<i::Mutex> lock_guard(&context_mutex_);
950
#endif  // V8_SHARED
951
  // Initialize the global objects
952
  Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
953
  HandleScope handle_scope(isolate);
954
  Local<Context> context = Context::New(isolate, NULL, global_template);
955
  ASSERT(!context.IsEmpty());
956
  Context::Scope scope(context);
957

    
958
#ifndef V8_SHARED
959
  i::Factory* factory = reinterpret_cast<i::Isolate*>(isolate)->factory();
960
  i::JSArguments js_args = i::FLAG_js_arguments;
961
  i::Handle<i::FixedArray> arguments_array =
962
      factory->NewFixedArray(js_args.argc);
963
  for (int j = 0; j < js_args.argc; j++) {
964
    i::Handle<i::String> arg =
965
        factory->NewStringFromUtf8(i::CStrVector(js_args[j]));
966
    arguments_array->set(j, *arg);
967
  }
968
  i::Handle<i::JSArray> arguments_jsarray =
969
      factory->NewJSArrayWithElements(arguments_array);
970
  context->Global()->Set(String::New("arguments"),
971
                         Utils::ToLocal(arguments_jsarray));
972
#endif  // V8_SHARED
973
  return handle_scope.Close(context);
974
}
975

    
976

    
977
void Shell::Exit(int exit_code) {
978
  // Use _exit instead of exit to avoid races between isolate
979
  // threads and static destructors.
980
  fflush(stdout);
981
  fflush(stderr);
982
  _exit(exit_code);
983
}
984

    
985

    
986
#ifndef V8_SHARED
987
struct CounterAndKey {
988
  Counter* counter;
989
  const char* key;
990
};
991

    
992

    
993
inline bool operator<(const CounterAndKey& lhs, const CounterAndKey& rhs) {
994
  return strcmp(lhs.key, rhs.key) < 0;
995
}
996
#endif  // V8_SHARED
997

    
998

    
999
void Shell::OnExit() {
1000
  LineEditor* line_editor = LineEditor::Get();
1001
  if (line_editor) line_editor->Close();
1002
#ifndef V8_SHARED
1003
  if (i::FLAG_dump_counters) {
1004
    int number_of_counters = 0;
1005
    for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
1006
      number_of_counters++;
1007
    }
1008
    CounterAndKey* counters = new CounterAndKey[number_of_counters];
1009
    int j = 0;
1010
    for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
1011
      counters[j].counter = i.CurrentValue();
1012
      counters[j].key = i.CurrentKey();
1013
    }
1014
    std::sort(counters, counters + number_of_counters);
1015
    printf("+----------------------------------------------------------------+"
1016
           "-------------+\n");
1017
    printf("| Name                                                           |"
1018
           " Value       |\n");
1019
    printf("+----------------------------------------------------------------+"
1020
           "-------------+\n");
1021
    for (j = 0; j < number_of_counters; j++) {
1022
      Counter* counter = counters[j].counter;
1023
      const char* key = counters[j].key;
1024
      if (counter->is_histogram()) {
1025
        printf("| c:%-60s | %11i |\n", key, counter->count());
1026
        printf("| t:%-60s | %11i |\n", key, counter->sample_total());
1027
      } else {
1028
        printf("| %-62s | %11i |\n", key, counter->count());
1029
      }
1030
    }
1031
    printf("+----------------------------------------------------------------+"
1032
           "-------------+\n");
1033
    delete [] counters;
1034
  }
1035
  delete counters_file_;
1036
  delete counter_map_;
1037
#endif  // V8_SHARED
1038
}
1039

    
1040

    
1041

    
1042
static FILE* FOpen(const char* path, const char* mode) {
1043
#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
1044
  FILE* result;
1045
  if (fopen_s(&result, path, mode) == 0) {
1046
    return result;
1047
  } else {
1048
    return NULL;
1049
  }
1050
#else
1051
  FILE* file = fopen(path, mode);
1052
  if (file == NULL) return NULL;
1053
  struct stat file_stat;
1054
  if (fstat(fileno(file), &file_stat) != 0) return NULL;
1055
  bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
1056
  if (is_regular_file) return file;
1057
  fclose(file);
1058
  return NULL;
1059
#endif
1060
}
1061

    
1062

    
1063
static char* ReadChars(Isolate* isolate, const char* name, int* size_out) {
1064
  // Release the V8 lock while reading files.
1065
  v8::Unlocker unlocker(isolate);
1066
  FILE* file = FOpen(name, "rb");
1067
  if (file == NULL) return NULL;
1068

    
1069
  fseek(file, 0, SEEK_END);
1070
  int size = ftell(file);
1071
  rewind(file);
1072

    
1073
  char* chars = new char[size + 1];
1074
  chars[size] = '\0';
1075
  for (int i = 0; i < size;) {
1076
    int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
1077
    i += read;
1078
  }
1079
  fclose(file);
1080
  *size_out = size;
1081
  return chars;
1082
}
1083

    
1084
static void ReadBufferWeakCallback(v8::Isolate* isolate,
1085
                                   Persistent<ArrayBuffer>* array_buffer,
1086
                                   uint8_t* data) {
1087
  size_t byte_length =
1088
      Local<ArrayBuffer>::New(isolate, *array_buffer)->ByteLength();
1089
  isolate->AdjustAmountOfExternalAllocatedMemory(
1090
      -static_cast<intptr_t>(byte_length));
1091

    
1092
  delete[] data;
1093
  array_buffer->Dispose();
1094
}
1095

    
1096

    
1097
void Shell::ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args) {
1098
  ASSERT(sizeof(char) == sizeof(uint8_t));  // NOLINT
1099
  String::Utf8Value filename(args[0]);
1100
  int length;
1101
  if (*filename == NULL) {
1102
    Throw("Error loading file");
1103
    return;
1104
  }
1105

    
1106
  Isolate* isolate = args.GetIsolate();
1107
  uint8_t* data = reinterpret_cast<uint8_t*>(
1108
      ReadChars(args.GetIsolate(), *filename, &length));
1109
  if (data == NULL) {
1110
    Throw("Error reading file");
1111
    return;
1112
  }
1113
  Handle<v8::ArrayBuffer> buffer = ArrayBuffer::New(data, length);
1114
  v8::Persistent<v8::ArrayBuffer> weak_handle(isolate, buffer);
1115
  weak_handle.MakeWeak(data, ReadBufferWeakCallback);
1116
  weak_handle.MarkIndependent();
1117
  isolate->AdjustAmountOfExternalAllocatedMemory(length);
1118

    
1119
  args.GetReturnValue().Set(buffer);
1120
}
1121

    
1122

    
1123
#ifndef V8_SHARED
1124
static char* ReadToken(char* data, char token) {
1125
  char* next = i::OS::StrChr(data, token);
1126
  if (next != NULL) {
1127
    *next = '\0';
1128
    return (next + 1);
1129
  }
1130

    
1131
  return NULL;
1132
}
1133

    
1134

    
1135
static char* ReadLine(char* data) {
1136
  return ReadToken(data, '\n');
1137
}
1138

    
1139

    
1140
static char* ReadWord(char* data) {
1141
  return ReadToken(data, ' ');
1142
}
1143
#endif  // V8_SHARED
1144

    
1145

    
1146
// Reads a file into a v8 string.
1147
Handle<String> Shell::ReadFile(Isolate* isolate, const char* name) {
1148
  int size = 0;
1149
  char* chars = ReadChars(isolate, name, &size);
1150
  if (chars == NULL) return Handle<String>();
1151
  Handle<String> result = String::New(chars, size);
1152
  delete[] chars;
1153
  return result;
1154
}
1155

    
1156

    
1157
void Shell::RunShell(Isolate* isolate) {
1158
  Locker locker(isolate);
1159
  HandleScope outer_scope(isolate);
1160
  v8::Local<v8::Context> context =
1161
      v8::Local<v8::Context>::New(isolate, evaluation_context_);
1162
  v8::Context::Scope context_scope(context);
1163
  PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1164
  Handle<String> name = String::New("(d8)");
1165
  LineEditor* console = LineEditor::Get();
1166
  printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
1167
  console->Open(isolate);
1168
  while (true) {
1169
    HandleScope inner_scope(isolate);
1170
    Handle<String> input = console->Prompt(Shell::kPrompt);
1171
    if (input.IsEmpty()) break;
1172
    ExecuteString(isolate, input, name, true, true);
1173
  }
1174
  printf("\n");
1175
}
1176

    
1177

    
1178
#ifndef V8_SHARED
1179
class ShellThread : public i::Thread {
1180
 public:
1181
  // Takes ownership of the underlying char array of |files|.
1182
  ShellThread(Isolate* isolate, char* files)
1183
      : Thread("d8:ShellThread"),
1184
        isolate_(isolate), files_(files) { }
1185

    
1186
  ~ShellThread() {
1187
    delete[] files_;
1188
  }
1189

    
1190
  virtual void Run();
1191
 private:
1192
  Isolate* isolate_;
1193
  char* files_;
1194
};
1195

    
1196

    
1197
void ShellThread::Run() {
1198
  char* ptr = files_;
1199
  while ((ptr != NULL) && (*ptr != '\0')) {
1200
    // For each newline-separated line.
1201
    char* next_line = ReadLine(ptr);
1202

    
1203
    if (*ptr == '#') {
1204
      // Skip comment lines.
1205
      ptr = next_line;
1206
      continue;
1207
    }
1208

    
1209
    // Prepare the context for this thread.
1210
    Locker locker(isolate_);
1211
    HandleScope outer_scope(isolate_);
1212
    Local<Context> thread_context =
1213
        Shell::CreateEvaluationContext(isolate_);
1214
    Context::Scope context_scope(thread_context);
1215
    PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate_));
1216

    
1217
    while ((ptr != NULL) && (*ptr != '\0')) {
1218
      HandleScope inner_scope(isolate_);
1219
      char* filename = ptr;
1220
      ptr = ReadWord(ptr);
1221

    
1222
      // Skip empty strings.
1223
      if (strlen(filename) == 0) {
1224
        continue;
1225
      }
1226

    
1227
      Handle<String> str = Shell::ReadFile(isolate_, filename);
1228
      if (str.IsEmpty()) {
1229
        printf("File '%s' not found\n", filename);
1230
        Shell::Exit(1);
1231
      }
1232

    
1233
      Shell::ExecuteString(isolate_, str, String::New(filename), false, false);
1234
    }
1235

    
1236
    ptr = next_line;
1237
  }
1238
}
1239
#endif  // V8_SHARED
1240

    
1241

    
1242
SourceGroup::~SourceGroup() {
1243
#ifndef V8_SHARED
1244
  delete thread_;
1245
  thread_ = NULL;
1246
#endif  // V8_SHARED
1247
}
1248

    
1249

    
1250
void SourceGroup::Execute(Isolate* isolate) {
1251
  bool exception_was_thrown = false;
1252
  for (int i = begin_offset_; i < end_offset_; ++i) {
1253
    const char* arg = argv_[i];
1254
    if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1255
      // Execute argument given to -e option directly.
1256
      HandleScope handle_scope(isolate);
1257
      Handle<String> file_name = String::New("unnamed");
1258
      Handle<String> source = String::New(argv_[i + 1]);
1259
      if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1260
        exception_was_thrown = true;
1261
        break;
1262
      }
1263
      ++i;
1264
    } else if (arg[0] == '-') {
1265
      // Ignore other options. They have been parsed already.
1266
    } else {
1267
      // Use all other arguments as names of files to load and run.
1268
      HandleScope handle_scope(isolate);
1269
      Handle<String> file_name = String::New(arg);
1270
      Handle<String> source = ReadFile(isolate, arg);
1271
      if (source.IsEmpty()) {
1272
        printf("Error reading '%s'\n", arg);
1273
        Shell::Exit(1);
1274
      }
1275
      if (!Shell::ExecuteString(isolate, source, file_name, false, true)) {
1276
        exception_was_thrown = true;
1277
        break;
1278
      }
1279
    }
1280
  }
1281
  if (exception_was_thrown != Shell::options.expected_to_throw) {
1282
    Shell::Exit(1);
1283
  }
1284
}
1285

    
1286

    
1287
Handle<String> SourceGroup::ReadFile(Isolate* isolate, const char* name) {
1288
  int size;
1289
  char* chars = ReadChars(isolate, name, &size);
1290
  if (chars == NULL) return Handle<String>();
1291
  Handle<String> result = String::New(chars, size);
1292
  delete[] chars;
1293
  return result;
1294
}
1295

    
1296

    
1297
#ifndef V8_SHARED
1298
i::Thread::Options SourceGroup::GetThreadOptions() {
1299
  // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1300
  // which is not enough to parse the big literal expressions used in tests.
1301
  // The stack size should be at least StackGuard::kLimitSize + some
1302
  // OS-specific padding for thread startup code.  2Mbytes seems to be enough.
1303
  return i::Thread::Options("IsolateThread", 2 * MB);
1304
}
1305

    
1306

    
1307
void SourceGroup::ExecuteInThread() {
1308
  Isolate* isolate = Isolate::New();
1309
  do {
1310
    next_semaphore_.Wait();
1311
    {
1312
      Isolate::Scope iscope(isolate);
1313
      Locker lock(isolate);
1314
      {
1315
        HandleScope scope(isolate);
1316
        PerIsolateData data(isolate);
1317
        Local<Context> context = Shell::CreateEvaluationContext(isolate);
1318
        {
1319
          Context::Scope cscope(context);
1320
          PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1321
          Execute(isolate);
1322
        }
1323
      }
1324
      if (Shell::options.send_idle_notification) {
1325
        const int kLongIdlePauseInMs = 1000;
1326
        V8::ContextDisposedNotification();
1327
        V8::IdleNotification(kLongIdlePauseInMs);
1328
      }
1329
    }
1330
    done_semaphore_.Signal();
1331
  } while (!Shell::options.last_run);
1332
  isolate->Dispose();
1333
}
1334

    
1335

    
1336
void SourceGroup::StartExecuteInThread() {
1337
  if (thread_ == NULL) {
1338
    thread_ = new IsolateThread(this);
1339
    thread_->Start();
1340
  }
1341
  next_semaphore_.Signal();
1342
}
1343

    
1344

    
1345
void SourceGroup::WaitForThread() {
1346
  if (thread_ == NULL) return;
1347
  if (Shell::options.last_run) {
1348
    thread_->Join();
1349
  } else {
1350
    done_semaphore_.Wait();
1351
  }
1352
}
1353
#endif  // V8_SHARED
1354

    
1355

    
1356
bool Shell::SetOptions(int argc, char* argv[]) {
1357
  for (int i = 0; i < argc; i++) {
1358
    if (strcmp(argv[i], "--stress-opt") == 0) {
1359
      options.stress_opt = true;
1360
      argv[i] = NULL;
1361
    } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1362
      options.stress_deopt = true;
1363
      argv[i] = NULL;
1364
    } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1365
      // No support for stressing if we can't use --always-opt.
1366
      options.stress_opt = false;
1367
      options.stress_deopt = false;
1368
    } else if (strcmp(argv[i], "--shell") == 0) {
1369
      options.interactive_shell = true;
1370
      argv[i] = NULL;
1371
    } else if (strcmp(argv[i], "--test") == 0) {
1372
      options.test_shell = true;
1373
      argv[i] = NULL;
1374
    } else if (strcmp(argv[i], "--send-idle-notification") == 0) {
1375
      options.send_idle_notification = true;
1376
      argv[i] = NULL;
1377
    } else if (strcmp(argv[i], "--preemption") == 0) {
1378
#ifdef V8_SHARED
1379
      printf("D8 with shared library does not support multi-threading\n");
1380
      return false;
1381
#else
1382
      options.use_preemption = true;
1383
      argv[i] = NULL;
1384
#endif  // V8_SHARED
1385
    } else if (strcmp(argv[i], "--nopreemption") == 0) {
1386
#ifdef V8_SHARED
1387
      printf("D8 with shared library does not support multi-threading\n");
1388
      return false;
1389
#else
1390
      options.use_preemption = false;
1391
      argv[i] = NULL;
1392
#endif  // V8_SHARED
1393
    } else if (strcmp(argv[i], "--preemption-interval") == 0) {
1394
#ifdef V8_SHARED
1395
      printf("D8 with shared library does not support multi-threading\n");
1396
      return false;
1397
#else
1398
      if (++i < argc) {
1399
        argv[i-1] = NULL;
1400
        char* end = NULL;
1401
        options.preemption_interval = strtol(argv[i], &end, 10);  // NOLINT
1402
        if (options.preemption_interval <= 0
1403
            || *end != '\0'
1404
            || errno == ERANGE) {
1405
          printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
1406
          return false;
1407
        }
1408
        argv[i] = NULL;
1409
      } else {
1410
        printf("Missing value for --preemption-interval\n");
1411
        return false;
1412
      }
1413
#endif  // V8_SHARED
1414
    } else if (strcmp(argv[i], "-f") == 0) {
1415
      // Ignore any -f flags for compatibility with other stand-alone
1416
      // JavaScript engines.
1417
      continue;
1418
    } else if (strcmp(argv[i], "--isolate") == 0) {
1419
#ifdef V8_SHARED
1420
      printf("D8 with shared library does not support multi-threading\n");
1421
      return false;
1422
#endif  // V8_SHARED
1423
      options.num_isolates++;
1424
    } else if (strcmp(argv[i], "-p") == 0) {
1425
#ifdef V8_SHARED
1426
      printf("D8 with shared library does not support multi-threading\n");
1427
      return false;
1428
#else
1429
      options.num_parallel_files++;
1430
#endif  // V8_SHARED
1431
    } else if (strcmp(argv[i], "--dump-heap-constants") == 0) {
1432
#ifdef V8_SHARED
1433
      printf("D8 with shared library does not support constant dumping\n");
1434
      return false;
1435
#else
1436
      options.dump_heap_constants = true;
1437
      argv[i] = NULL;
1438
#endif
1439
    } else if (strcmp(argv[i], "--throws") == 0) {
1440
      options.expected_to_throw = true;
1441
      argv[i] = NULL;
1442
    }
1443
#ifdef V8_SHARED
1444
    else if (strcmp(argv[i], "--dump-counters") == 0) {
1445
      printf("D8 with shared library does not include counters\n");
1446
      return false;
1447
    } else if (strcmp(argv[i], "--debugger") == 0) {
1448
      printf("Javascript debugger not included\n");
1449
      return false;
1450
    }
1451
#endif  // V8_SHARED
1452
  }
1453

    
1454
#ifndef V8_SHARED
1455
  // Run parallel threads if we are not using --isolate
1456
  options.parallel_files = new char*[options.num_parallel_files];
1457
  int parallel_files_set = 0;
1458
  for (int i = 1; i < argc; i++) {
1459
    if (argv[i] == NULL) continue;
1460
    if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
1461
      if (options.num_isolates > 1) {
1462
        printf("-p is not compatible with --isolate\n");
1463
        return false;
1464
      }
1465
      argv[i] = NULL;
1466
      i++;
1467
      options.parallel_files[parallel_files_set] = argv[i];
1468
      parallel_files_set++;
1469
      argv[i] = NULL;
1470
    }
1471
  }
1472
  if (parallel_files_set != options.num_parallel_files) {
1473
    printf("-p requires a file containing a list of files as parameter\n");
1474
    return false;
1475
  }
1476
#endif  // V8_SHARED
1477

    
1478
  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1479

    
1480
  // Set up isolated source groups.
1481
  options.isolate_sources = new SourceGroup[options.num_isolates];
1482
  SourceGroup* current = options.isolate_sources;
1483
  current->Begin(argv, 1);
1484
  for (int i = 1; i < argc; i++) {
1485
    const char* str = argv[i];
1486
    if (strcmp(str, "--isolate") == 0) {
1487
      current->End(i);
1488
      current++;
1489
      current->Begin(argv, i + 1);
1490
    } else if (strncmp(argv[i], "--", 2) == 0) {
1491
      printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
1492
    }
1493
  }
1494
  current->End(argc);
1495

    
1496
  return true;
1497
}
1498

    
1499

    
1500
int Shell::RunMain(Isolate* isolate, int argc, char* argv[]) {
1501
#ifndef V8_SHARED
1502
  i::List<i::Thread*> threads(1);
1503
  if (options.parallel_files != NULL) {
1504
    for (int i = 0; i < options.num_parallel_files; i++) {
1505
      char* files = NULL;
1506
      { Locker lock(isolate);
1507
        int size = 0;
1508
        files = ReadChars(isolate, options.parallel_files[i], &size);
1509
      }
1510
      if (files == NULL) {
1511
        printf("File list '%s' not found\n", options.parallel_files[i]);
1512
        Exit(1);
1513
      }
1514
      ShellThread* thread = new ShellThread(isolate, files);
1515
      thread->Start();
1516
      threads.Add(thread);
1517
    }
1518
  }
1519
  for (int i = 1; i < options.num_isolates; ++i) {
1520
    options.isolate_sources[i].StartExecuteInThread();
1521
  }
1522
#endif  // V8_SHARED
1523
  {  // NOLINT
1524
    Locker lock(isolate);
1525
    {
1526
      HandleScope scope(isolate);
1527
      Local<Context> context = CreateEvaluationContext(isolate);
1528
      if (options.last_run) {
1529
        // Keep using the same context in the interactive shell.
1530
        evaluation_context_.Reset(isolate, context);
1531
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
1532
        // If the interactive debugger is enabled make sure to activate
1533
        // it before running the files passed on the command line.
1534
        if (i::FLAG_debugger) {
1535
          InstallUtilityScript(isolate);
1536
        }
1537
#endif  // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
1538
      }
1539
      {
1540
        Context::Scope cscope(context);
1541
        PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
1542
        options.isolate_sources[0].Execute(isolate);
1543
      }
1544
    }
1545
    if (!options.last_run) {
1546
      if (options.send_idle_notification) {
1547
        const int kLongIdlePauseInMs = 1000;
1548
        V8::ContextDisposedNotification();
1549
        V8::IdleNotification(kLongIdlePauseInMs);
1550
      }
1551
    }
1552

    
1553
#ifndef V8_SHARED
1554
    // Start preemption if threads have been created and preemption is enabled.
1555
    if (threads.length() > 0
1556
        && options.use_preemption) {
1557
      Locker::StartPreemption(isolate, options.preemption_interval);
1558
    }
1559
#endif  // V8_SHARED
1560
  }
1561

    
1562
#ifndef V8_SHARED
1563
  for (int i = 1; i < options.num_isolates; ++i) {
1564
    options.isolate_sources[i].WaitForThread();
1565
  }
1566

    
1567
  for (int i = 0; i < threads.length(); i++) {
1568
    i::Thread* thread = threads[i];
1569
    thread->Join();
1570
    delete thread;
1571
  }
1572

    
1573
  if (threads.length() > 0 && options.use_preemption) {
1574
    Locker lock(isolate);
1575
    Locker::StopPreemption(isolate);
1576
  }
1577
#endif  // V8_SHARED
1578
  return 0;
1579
}
1580

    
1581

    
1582
#ifdef V8_SHARED
1583
static void SetStandaloneFlagsViaCommandLine() {
1584
  int fake_argc = 2;
1585
  char **fake_argv = new char*[2];
1586
  fake_argv[0] = NULL;
1587
  fake_argv[1] = strdup("--trace-hydrogen-file=hydrogen.cfg");
1588
  v8::V8::SetFlagsFromCommandLine(&fake_argc, fake_argv, false);
1589
  free(fake_argv[1]);
1590
  delete[] fake_argv;
1591
}
1592
#endif
1593

    
1594

    
1595
#ifndef V8_SHARED
1596
static void DumpHeapConstants(i::Isolate* isolate) {
1597
  i::Heap* heap = isolate->heap();
1598

    
1599
  // Dump the INSTANCE_TYPES table to the console.
1600
  printf("# List of known V8 instance types.\n");
1601
#define DUMP_TYPE(T) printf("  %d: \"%s\",\n", i::T, #T);
1602
  printf("INSTANCE_TYPES = {\n");
1603
  INSTANCE_TYPE_LIST(DUMP_TYPE)
1604
  printf("}\n");
1605
#undef DUMP_TYPE
1606

    
1607
  // Dump the KNOWN_MAP table to the console.
1608
  printf("\n# List of known V8 maps.\n");
1609
#define ROOT_LIST_CASE(type, name, camel_name) \
1610
  if (n == NULL && o == heap->name()) n = #camel_name;
1611
#define STRUCT_LIST_CASE(upper_name, camel_name, name) \
1612
  if (n == NULL && o == heap->name##_map()) n = #camel_name "Map";
1613
  i::HeapObjectIterator it(heap->map_space());
1614
  printf("KNOWN_MAPS = {\n");
1615
  for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
1616
    i::Map* m = i::Map::cast(o);
1617
    const char* n = NULL;
1618
    intptr_t p = reinterpret_cast<intptr_t>(m) & 0xfffff;
1619
    int t = m->instance_type();
1620
    ROOT_LIST(ROOT_LIST_CASE)
1621
    STRUCT_LIST(STRUCT_LIST_CASE)
1622
    if (n == NULL) continue;
1623
    printf("  0x%05" V8PRIxPTR ": (%d, \"%s\"),\n", p, t, n);
1624
  }
1625
  printf("}\n");
1626
#undef STRUCT_LIST_CASE
1627
#undef ROOT_LIST_CASE
1628

    
1629
  // Dump the KNOWN_OBJECTS table to the console.
1630
  printf("\n# List of known V8 objects.\n");
1631
#define ROOT_LIST_CASE(type, name, camel_name) \
1632
  if (n == NULL && o == heap->name()) n = #camel_name;
1633
  i::OldSpaces spit(heap);
1634
  printf("KNOWN_OBJECTS = {\n");
1635
  for (i::PagedSpace* s = spit.next(); s != NULL; s = spit.next()) {
1636
    i::HeapObjectIterator it(s);
1637
    const char* sname = AllocationSpaceName(s->identity());
1638
    for (i::Object* o = it.Next(); o != NULL; o = it.Next()) {
1639
      const char* n = NULL;
1640
      intptr_t p = reinterpret_cast<intptr_t>(o) & 0xfffff;
1641
      ROOT_LIST(ROOT_LIST_CASE)
1642
      if (n == NULL) continue;
1643
      printf("  (\"%s\", 0x%05" V8PRIxPTR "): \"%s\",\n", sname, p, n);
1644
    }
1645
  }
1646
  printf("}\n");
1647
#undef ROOT_LIST_CASE
1648
}
1649
#endif  // V8_SHARED
1650

    
1651

    
1652
class ShellArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
1653
 public:
1654
  virtual void* Allocate(size_t length) {
1655
    void* result = malloc(length);
1656
    memset(result, 0, length);
1657
    return result;
1658
  }
1659
  virtual void* AllocateUninitialized(size_t length) {
1660
    return malloc(length);
1661
  }
1662
  virtual void Free(void* data, size_t) { free(data); }
1663
  // TODO(dslomov): Remove when v8:2823 is fixed.
1664
  virtual void Free(void* data) {
1665
#ifndef V8_SHARED
1666
    UNREACHABLE();
1667
#endif
1668
  }
1669
};
1670

    
1671

    
1672
int Shell::Main(int argc, char* argv[]) {
1673
  if (!SetOptions(argc, argv)) return 1;
1674
  v8::V8::InitializeICU();
1675
#ifndef V8_SHARED
1676
  i::FLAG_trace_hydrogen_file = "hydrogen.cfg";
1677
#else
1678
  SetStandaloneFlagsViaCommandLine();
1679
#endif
1680
  v8::SetDefaultResourceConstraintsForCurrentPlatform();
1681
  ShellArrayBufferAllocator array_buffer_allocator;
1682
  v8::V8::SetArrayBufferAllocator(&array_buffer_allocator);
1683
  int result = 0;
1684
  Isolate* isolate = Isolate::GetCurrent();
1685
  DumbLineEditor dumb_line_editor(isolate);
1686
  {
1687
    Initialize(isolate);
1688
#ifdef ENABLE_VTUNE_JIT_INTERFACE
1689
    vTune::InitializeVtuneForV8();
1690
#endif
1691
    PerIsolateData data(isolate);
1692
    InitializeDebugger(isolate);
1693

    
1694
#ifndef V8_SHARED
1695
    if (options.dump_heap_constants) {
1696
      DumpHeapConstants(reinterpret_cast<i::Isolate*>(isolate));
1697
      return 0;
1698
    }
1699
#endif
1700

    
1701
    if (options.stress_opt || options.stress_deopt) {
1702
      Testing::SetStressRunType(options.stress_opt
1703
                                ? Testing::kStressTypeOpt
1704
                                : Testing::kStressTypeDeopt);
1705
      int stress_runs = Testing::GetStressRuns();
1706
      for (int i = 0; i < stress_runs && result == 0; i++) {
1707
        printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
1708
        Testing::PrepareStressRun(i);
1709
        options.last_run = (i == stress_runs - 1);
1710
        result = RunMain(isolate, argc, argv);
1711
      }
1712
      printf("======== Full Deoptimization =======\n");
1713
      Testing::DeoptimizeAll();
1714
#if !defined(V8_SHARED)
1715
    } else if (i::FLAG_stress_runs > 0) {
1716
      int stress_runs = i::FLAG_stress_runs;
1717
      for (int i = 0; i < stress_runs && result == 0; i++) {
1718
        printf("============ Run %d/%d ============\n", i + 1, stress_runs);
1719
        options.last_run = (i == stress_runs - 1);
1720
        result = RunMain(isolate, argc, argv);
1721
      }
1722
#endif
1723
    } else {
1724
      result = RunMain(isolate, argc, argv);
1725
    }
1726

    
1727

    
1728
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
1729
    // Run remote debugger if requested, but never on --test
1730
    if (i::FLAG_remote_debugger && !options.test_shell) {
1731
      InstallUtilityScript(isolate);
1732
      RunRemoteDebugger(isolate, i::FLAG_debugger_port);
1733
      return 0;
1734
    }
1735
#endif  // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
1736

    
1737
    // Run interactive shell if explicitly requested or if no script has been
1738
    // executed, but never on --test
1739

    
1740
    if (( options.interactive_shell || !options.script_executed )
1741
        && !options.test_shell ) {
1742
#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
1743
      if (!i::FLAG_debugger) {
1744
        InstallUtilityScript(isolate);
1745
      }
1746
#endif  // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
1747
      RunShell(isolate);
1748
    }
1749
  }
1750
  V8::Dispose();
1751

    
1752
  OnExit();
1753

    
1754
  return result;
1755
}
1756

    
1757
}  // namespace v8
1758

    
1759

    
1760
#ifndef GOOGLE3
1761
int main(int argc, char* argv[]) {
1762
  return v8::Shell::Main(argc, argv);
1763
}
1764
#endif