blob: 9eccc7e4fe4ed6fd0786c0bbeb62a06ffb277498 [file] [log] [blame]
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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
Ben Murdoch69a99ed2011-11-30 16:03:39 +000029#ifdef USING_V8_SHARED // Defined when linking against shared lib on Windows.
30#define V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000031#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000032
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000033#ifdef COMPRESS_STARTUP_DATA_BZ2
34#include <bzlib.h>
35#endif
36
37#include <errno.h>
38#include <stdlib.h>
39#include <string.h>
Ben Murdoch69a99ed2011-11-30 16:03:39 +000040#include <sys/stat.h>
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000041
Ben Murdoch69a99ed2011-11-30 16:03:39 +000042#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000043#include <assert.h>
44#include "../include/v8-testing.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000045#endif // V8_SHARED
Steve Block44f0eee2011-05-26 01:26:41 +010046
Steve Blocka7e24c12009-10-30 11:49:00 +000047#include "d8.h"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000048
Ben Murdoch69a99ed2011-11-30 16:03:39 +000049#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000050#include "api.h"
51#include "checks.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000052#include "d8-debug.h"
53#include "debug.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000054#include "natives.h"
55#include "platform.h"
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000056#include "v8.h"
Ben Murdoch69a99ed2011-11-30 16:03:39 +000057#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +000058
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000059#if !defined(_WIN32) && !defined(_WIN64)
60#include <unistd.h> // NOLINT
61#endif
62
Ben Murdoch69a99ed2011-11-30 16:03:39 +000063#ifndef ASSERT
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000064#define ASSERT(condition) assert(condition)
Ben Murdoch69a99ed2011-11-30 16:03:39 +000065#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000066
67namespace v8 {
68
69
Ben Murdoch69a99ed2011-11-30 16:03:39 +000070#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +000071LineEditor *LineEditor::first_ = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000072const char* Shell::kHistoryFileName = ".d8_history";
Ben Murdoch589d6972011-11-30 16:04:58 +000073const int Shell::kMaxHistoryEntries = 1000;
Steve Blocka7e24c12009-10-30 11:49:00 +000074
75
76LineEditor::LineEditor(Type type, const char* name)
77 : type_(type),
78 name_(name),
79 next_(first_) {
80 first_ = this;
81}
82
83
84LineEditor* LineEditor::Get() {
85 LineEditor* current = first_;
86 LineEditor* best = current;
87 while (current != NULL) {
88 if (current->type_ > best->type_)
89 best = current;
90 current = current->next_;
91 }
92 return best;
93}
94
95
96class DumbLineEditor: public LineEditor {
97 public:
98 DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
Ben Murdoch589d6972011-11-30 16:04:58 +000099 virtual i::SmartArrayPointer<char> Prompt(const char* prompt);
Steve Blocka7e24c12009-10-30 11:49:00 +0000100};
101
102
103static DumbLineEditor dumb_line_editor;
104
105
Ben Murdoch589d6972011-11-30 16:04:58 +0000106i::SmartArrayPointer<char> DumbLineEditor::Prompt(const char* prompt) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000107 static const int kBufferSize = 256;
108 char buffer[kBufferSize];
109 printf("%s", prompt);
110 char* str = fgets(buffer, kBufferSize, stdin);
Ben Murdoch589d6972011-11-30 16:04:58 +0000111 return i::SmartArrayPointer<char>(str ? i::StrDup(str) : str);
Steve Blocka7e24c12009-10-30 11:49:00 +0000112}
113
114
115CounterMap* Shell::counter_map_;
116i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
117CounterCollection Shell::local_counters_;
118CounterCollection* Shell::counters_ = &local_counters_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000119i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
Steve Blocka7e24c12009-10-30 11:49:00 +0000120Persistent<Context> Shell::utility_context_;
Ben Murdoch589d6972011-11-30 16:04:58 +0000121LineEditor* Shell::console = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000122#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000123
Steve Blocka7e24c12009-10-30 11:49:00 +0000124Persistent<Context> Shell::evaluation_context_;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000125ShellOptions Shell::options;
126const char* Shell::kPrompt = "d8> ";
Steve Blocka7e24c12009-10-30 11:49:00 +0000127
128
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000129#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000130bool CounterMap::Match(void* key1, void* key2) {
131 const char* name1 = reinterpret_cast<const char*>(key1);
132 const char* name2 = reinterpret_cast<const char*>(key2);
133 return strcmp(name1, name2) == 0;
134}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000135#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000136
137
138// Converts a V8 value to a C string.
Steve Block6ded16b2010-05-10 14:33:55 +0100139const char* Shell::ToCString(const v8::String::Utf8Value& value) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 return *value ? *value : "<string conversion failed>";
141}
142
143
144// Executes a string within the current v8 context.
145bool Shell::ExecuteString(Handle<String> source,
146 Handle<Value> name,
147 bool print_result,
148 bool report_exceptions) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000149#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000150 bool FLAG_debugger = i::FLAG_debugger;
151#else
152 bool FLAG_debugger = false;
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000153#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +0000154 HandleScope handle_scope;
155 TryCatch try_catch;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000156 options.script_executed = true;
157 if (FLAG_debugger) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000158 // When debugging make exceptions appear to be uncaught.
159 try_catch.SetVerbose(true);
160 }
161 Handle<Script> script = Script::Compile(source, name);
162 if (script.IsEmpty()) {
163 // Print errors that happened during compilation.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000164 if (report_exceptions && !FLAG_debugger)
Steve Blocka7e24c12009-10-30 11:49:00 +0000165 ReportException(&try_catch);
166 return false;
167 } else {
168 Handle<Value> result = script->Run();
169 if (result.IsEmpty()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100170 ASSERT(try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000171 // Print errors that happened during execution.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000172 if (report_exceptions && !FLAG_debugger)
Steve Blocka7e24c12009-10-30 11:49:00 +0000173 ReportException(&try_catch);
174 return false;
175 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100176 ASSERT(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 if (print_result && !result->IsUndefined()) {
178 // If all went well and the result wasn't undefined then print
179 // the returned value.
180 v8::String::Utf8Value str(result);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000181 size_t count = fwrite(*str, sizeof(**str), str.length(), stdout);
182 (void) count; // Silence GCC-4.5.x "unused result" warning.
Ben Murdoch589d6972011-11-30 16:04:58 +0000183 printf("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000184 }
185 return true;
186 }
187 }
188}
189
190
191Handle<Value> Shell::Print(const Arguments& args) {
192 Handle<Value> val = Write(args);
193 printf("\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000194 fflush(stdout);
Steve Blocka7e24c12009-10-30 11:49:00 +0000195 return val;
196}
197
198
199Handle<Value> Shell::Write(const Arguments& args) {
200 for (int i = 0; i < args.Length(); i++) {
201 HandleScope handle_scope;
202 if (i != 0) {
203 printf(" ");
204 }
205 v8::String::Utf8Value str(args[i]);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000206 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
Steve Blockd0582a62009-12-15 09:54:21 +0000207 if (n != str.length()) {
208 printf("Error in fwrite\n");
Ben Murdoch589d6972011-11-30 16:04:58 +0000209 Exit(1);
Steve Blockd0582a62009-12-15 09:54:21 +0000210 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000211 }
212 return Undefined();
213}
214
215
Ben Murdoch589d6972011-11-30 16:04:58 +0000216Handle<Value> Shell::EnableProfiler(const Arguments& args) {
217 V8::ResumeProfiler();
218 return Undefined();
219}
220
221
222Handle<Value> Shell::DisableProfiler(const Arguments& args) {
223 V8::PauseProfiler();
224 return Undefined();
225}
226
227
Steve Blocka7e24c12009-10-30 11:49:00 +0000228Handle<Value> Shell::Read(const Arguments& args) {
229 String::Utf8Value file(args[0]);
230 if (*file == NULL) {
231 return ThrowException(String::New("Error loading file"));
232 }
233 Handle<String> source = ReadFile(*file);
234 if (source.IsEmpty()) {
235 return ThrowException(String::New("Error loading file"));
236 }
237 return source;
238}
239
240
241Handle<Value> Shell::ReadLine(const Arguments& args) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000242 static const int kBufferSize = 256;
243 char buffer[kBufferSize];
244 Handle<String> accumulator = String::New("");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000245 int length;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000246 while (true) {
247 // Continue reading if the line ends with an escape '\\' or the line has
248 // not been fully read into the buffer yet (does not end with '\n').
249 // If fgets gets an error, just give up.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000250 if (fgets(buffer, kBufferSize, stdin) == NULL) return Null();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000251 length = static_cast<int>(strlen(buffer));
252 if (length == 0) {
253 return accumulator;
254 } else if (buffer[length-1] != '\n') {
255 accumulator = String::Concat(accumulator, String::New(buffer, length));
256 } else if (length > 1 && buffer[length-2] == '\\') {
257 buffer[length-2] = '\n';
258 accumulator = String::Concat(accumulator, String::New(buffer, length-1));
259 } else {
260 return String::Concat(accumulator, String::New(buffer, length-1));
261 }
262 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000263}
264
265
266Handle<Value> Shell::Load(const Arguments& args) {
267 for (int i = 0; i < args.Length(); i++) {
268 HandleScope handle_scope;
269 String::Utf8Value file(args[i]);
270 if (*file == NULL) {
271 return ThrowException(String::New("Error loading file"));
272 }
273 Handle<String> source = ReadFile(*file);
274 if (source.IsEmpty()) {
275 return ThrowException(String::New("Error loading file"));
276 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000277 if (!ExecuteString(source, String::New(*file), false, true)) {
Steve Blockd0582a62009-12-15 09:54:21 +0000278 return ThrowException(String::New("Error executing file"));
Steve Blocka7e24c12009-10-30 11:49:00 +0000279 }
280 }
281 return Undefined();
282}
283
284
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000285Handle<Value> Shell::CreateExternalArray(const Arguments& args,
286 ExternalArrayType type,
287 size_t element_size) {
288 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 ||
289 element_size == 8);
290 if (args.Length() != 1) {
291 return ThrowException(
292 String::New("Array constructor needs one parameter."));
293 }
294 static const int kMaxLength = 0x3fffffff;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000295#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000296 ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000297#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000298 size_t length = 0;
299 if (args[0]->IsUint32()) {
300 length = args[0]->Uint32Value();
Ben Murdoch589d6972011-11-30 16:04:58 +0000301 } else {
302 Local<Number> number = args[0]->ToNumber();
303 if (number.IsEmpty() || !number->IsNumber()) {
304 return ThrowException(String::New("Array length must be a number."));
305 }
306 int32_t raw_length = number->ToInt32()->Int32Value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000307 if (raw_length < 0) {
308 return ThrowException(String::New("Array length must not be negative."));
309 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000310 if (raw_length > static_cast<int32_t>(kMaxLength)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000311 return ThrowException(
312 String::New("Array length exceeds maximum length."));
313 }
314 length = static_cast<size_t>(raw_length);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000315 }
316 if (length > static_cast<size_t>(kMaxLength)) {
317 return ThrowException(String::New("Array length exceeds maximum length."));
318 }
319 void* data = calloc(length, element_size);
320 if (data == NULL) {
321 return ThrowException(String::New("Memory allocation failed."));
322 }
323 Handle<Object> array = Object::New();
324 Persistent<Object> persistent_array = Persistent<Object>::New(array);
325 persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
326 persistent_array.MarkIndependent();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000327 array->SetIndexedPropertiesToExternalArrayData(data, type,
328 static_cast<int>(length));
329 array->Set(String::New("length"),
330 Int32::New(static_cast<int32_t>(length)), ReadOnly);
331 array->Set(String::New("BYTES_PER_ELEMENT"),
332 Int32::New(static_cast<int32_t>(element_size)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000333 return array;
334}
335
336
337void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
338 free(data);
339 object.Dispose();
340}
341
342
343Handle<Value> Shell::Int8Array(const Arguments& args) {
344 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
345}
346
347
348Handle<Value> Shell::Uint8Array(const Arguments& args) {
349 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t));
350}
351
352
353Handle<Value> Shell::Int16Array(const Arguments& args) {
354 return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t));
355}
356
357
358Handle<Value> Shell::Uint16Array(const Arguments& args) {
359 return CreateExternalArray(args, kExternalUnsignedShortArray,
360 sizeof(uint16_t));
361}
362
363
364Handle<Value> Shell::Int32Array(const Arguments& args) {
365 return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t));
366}
367
368
369Handle<Value> Shell::Uint32Array(const Arguments& args) {
370 return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t));
371}
372
373
374Handle<Value> Shell::Float32Array(const Arguments& args) {
375 return CreateExternalArray(args, kExternalFloatArray,
376 sizeof(float)); // NOLINT
377}
378
379
380Handle<Value> Shell::Float64Array(const Arguments& args) {
381 return CreateExternalArray(args, kExternalDoubleArray,
382 sizeof(double)); // NOLINT
383}
384
385
386Handle<Value> Shell::PixelArray(const Arguments& args) {
387 return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t));
388}
389
390
Steve Blocka7e24c12009-10-30 11:49:00 +0000391Handle<Value> Shell::Yield(const Arguments& args) {
392 v8::Unlocker unlocker;
393 return Undefined();
394}
395
396
397Handle<Value> Shell::Quit(const Arguments& args) {
398 int exit_code = args[0]->Int32Value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000399#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000400 OnExit();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000401#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000402 exit(exit_code);
403 return Undefined();
404}
405
406
407Handle<Value> Shell::Version(const Arguments& args) {
408 return String::New(V8::GetVersion());
409}
410
411
412void Shell::ReportException(v8::TryCatch* try_catch) {
413 HandleScope handle_scope;
414 v8::String::Utf8Value exception(try_catch->Exception());
415 const char* exception_string = ToCString(exception);
416 Handle<Message> message = try_catch->Message();
417 if (message.IsEmpty()) {
418 // V8 didn't provide any extra information about this error; just
419 // print the exception.
420 printf("%s\n", exception_string);
421 } else {
422 // Print (filename):(line number): (message).
423 v8::String::Utf8Value filename(message->GetScriptResourceName());
424 const char* filename_string = ToCString(filename);
425 int linenum = message->GetLineNumber();
426 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
427 // Print line of source code.
428 v8::String::Utf8Value sourceline(message->GetSourceLine());
429 const char* sourceline_string = ToCString(sourceline);
430 printf("%s\n", sourceline_string);
431 // Print wavy underline (GetUnderline is deprecated).
432 int start = message->GetStartColumn();
433 for (int i = 0; i < start; i++) {
434 printf(" ");
435 }
436 int end = message->GetEndColumn();
437 for (int i = start; i < end; i++) {
438 printf("^");
439 }
440 printf("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000441 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
442 if (stack_trace.length() > 0) {
443 const char* stack_trace_string = ToCString(stack_trace);
444 printf("%s\n", stack_trace_string);
445 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000446 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000447 printf("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000448}
449
450
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000451#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000452Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
453 HandleScope handle_scope;
454 Context::Scope context_scope(utility_context_);
455 Handle<Object> global = utility_context_->Global();
456 Handle<Value> fun = global->Get(String::New("GetCompletions"));
457 static const int kArgc = 3;
458 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
459 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
460 return handle_scope.Close(Handle<Array>::Cast(val));
461}
462
463
464#ifdef ENABLE_DEBUGGER_SUPPORT
465Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
466 Context::Scope context_scope(utility_context_);
467 Handle<Object> global = utility_context_->Global();
468 Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
469 static const int kArgc = 1;
470 Handle<Value> argv[kArgc] = { message };
471 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
472 return Handle<Object>::Cast(val);
473}
474
475
476Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
477 Context::Scope context_scope(utility_context_);
478 Handle<Object> global = utility_context_->Global();
479 Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
480 static const int kArgc = 1;
481 Handle<Value> argv[kArgc] = { command };
482 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
483 return val;
484}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000485#endif // ENABLE_DEBUGGER_SUPPORT
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000486#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000487
488
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000489#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000490int32_t* Counter::Bind(const char* name, bool is_histogram) {
491 int i;
492 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
493 name_[i] = static_cast<char>(name[i]);
494 name_[i] = '\0';
495 is_histogram_ = is_histogram;
496 return ptr();
497}
498
499
500void Counter::AddSample(int32_t sample) {
501 count_++;
502 sample_total_ += sample;
503}
504
505
506CounterCollection::CounterCollection() {
507 magic_number_ = 0xDEADFACE;
508 max_counters_ = kMaxCounters;
509 max_name_size_ = Counter::kMaxNameSize;
510 counters_in_use_ = 0;
511}
512
513
514Counter* CounterCollection::GetNextCounter() {
515 if (counters_in_use_ == kMaxCounters) return NULL;
516 return &counters_[counters_in_use_++];
517}
518
519
520void Shell::MapCounters(const char* name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000521 counters_file_ = i::OS::MemoryMappedFile::create(
522 name, sizeof(CounterCollection), &local_counters_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000523 void* memory = (counters_file_ == NULL) ?
524 NULL : counters_file_->memory();
525 if (memory == NULL) {
526 printf("Could not map counters file %s\n", name);
Ben Murdoch589d6972011-11-30 16:04:58 +0000527 Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000528 }
529 counters_ = static_cast<CounterCollection*>(memory);
530 V8::SetCounterFunction(LookupCounter);
531 V8::SetCreateHistogramFunction(CreateHistogram);
532 V8::SetAddHistogramSampleFunction(AddHistogramSample);
533}
534
535
536int CounterMap::Hash(const char* name) {
537 int h = 0;
538 int c;
539 while ((c = *name++) != 0) {
540 h += h << 5;
541 h += c;
542 }
543 return h;
544}
545
546
547Counter* Shell::GetCounter(const char* name, bool is_histogram) {
548 Counter* counter = counter_map_->Lookup(name);
549
550 if (counter == NULL) {
551 counter = counters_->GetNextCounter();
552 if (counter != NULL) {
553 counter_map_->Set(name, counter);
554 counter->Bind(name, is_histogram);
555 }
556 } else {
557 ASSERT(counter->is_histogram() == is_histogram);
558 }
559 return counter;
560}
561
562
563int* Shell::LookupCounter(const char* name) {
564 Counter* counter = GetCounter(name, false);
565
566 if (counter != NULL) {
567 return counter->ptr();
568 } else {
569 return NULL;
570 }
571}
572
573
574void* Shell::CreateHistogram(const char* name,
575 int min,
576 int max,
577 size_t buckets) {
578 return GetCounter(name, true);
579}
580
581
582void Shell::AddHistogramSample(void* histogram, int sample) {
583 Counter* counter = reinterpret_cast<Counter*>(histogram);
584 counter->AddSample(sample);
585}
586
587
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000588void Shell::InstallUtilityScript() {
589 Locker lock;
Steve Blocka7e24c12009-10-30 11:49:00 +0000590 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000591 // If we use the utility context, we have to set the security tokens so that
592 // utility, evaluation and debug context can all access each other.
Steve Blocka7e24c12009-10-30 11:49:00 +0000593 utility_context_->SetSecurityToken(Undefined());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000594 evaluation_context_->SetSecurityToken(Undefined());
Steve Blocka7e24c12009-10-30 11:49:00 +0000595 Context::Scope utility_scope(utility_context_);
596
Steve Blocka7e24c12009-10-30 11:49:00 +0000597#ifdef ENABLE_DEBUGGER_SUPPORT
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000598 if (i::FLAG_debugger) printf("JavaScript debugger enabled\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000599 // Install the debugger object in the utility scope
Steve Block44f0eee2011-05-26 01:26:41 +0100600 i::Debug* debug = i::Isolate::Current()->debug();
601 debug->Load();
602 i::Handle<i::JSObject> js_debug
603 = i::Handle<i::JSObject>(debug->debug_context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +0000604 utility_context_->Global()->Set(String::New("$debug"),
Steve Block44f0eee2011-05-26 01:26:41 +0100605 Utils::ToLocal(js_debug));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000606 debug->debug_context()->set_security_token(HEAP->undefined_value());
607#endif // ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +0000608
609 // Run the d8 shell utility script in the utility context
610 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000611 i::Vector<const char> shell_source =
612 i::NativesCollection<i::D8>::GetRawScriptSource(source_index);
613 i::Vector<const char> shell_source_name =
614 i::NativesCollection<i::D8>::GetScriptName(source_index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000615 Handle<String> source = String::New(shell_source.start(),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000616 shell_source.length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 Handle<String> name = String::New(shell_source_name.start(),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000618 shell_source_name.length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000619 Handle<Script> script = Script::Compile(source, name);
620 script->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +0000621 // Mark the d8 shell script as native to avoid it showing up as normal source
622 // in the debugger.
Steve Block6ded16b2010-05-10 14:33:55 +0100623 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
624 i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
625 ? i::Handle<i::Script>(i::Script::cast(
626 i::JSFunction::cast(*compiled_script)->shared()->script()))
627 : i::Handle<i::Script>(i::Script::cast(
628 i::SharedFunctionInfo::cast(*compiled_script)->script()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000629 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
630
Steve Blocka7e24c12009-10-30 11:49:00 +0000631#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +0000632 // Start the in-process debugger if requested.
633 if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
634 v8::Debug::SetDebugEventListener(HandleDebugEvent);
635 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000636#endif // ENABLE_DEBUGGER_SUPPORT
637}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000638#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000639
640
641#ifdef COMPRESS_STARTUP_DATA_BZ2
642class BZip2Decompressor : public v8::StartupDataDecompressor {
643 public:
644 virtual ~BZip2Decompressor() { }
645
646 protected:
647 virtual int DecompressData(char* raw_data,
648 int* raw_data_size,
649 const char* compressed_data,
650 int compressed_data_size) {
651 ASSERT_EQ(v8::StartupData::kBZip2,
652 v8::V8::GetCompressedStartupDataAlgorithm());
653 unsigned int decompressed_size = *raw_data_size;
654 int result =
655 BZ2_bzBuffToBuffDecompress(raw_data,
656 &decompressed_size,
657 const_cast<char*>(compressed_data),
658 compressed_data_size,
659 0, 1);
660 if (result == BZ_OK) {
661 *raw_data_size = decompressed_size;
662 }
663 return result;
664 }
665};
Steve Blocka7e24c12009-10-30 11:49:00 +0000666#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000667
668Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
669 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
670 global_template->Set(String::New("print"), FunctionTemplate::New(Print));
671 global_template->Set(String::New("write"), FunctionTemplate::New(Write));
672 global_template->Set(String::New("read"), FunctionTemplate::New(Read));
673 global_template->Set(String::New("readline"),
674 FunctionTemplate::New(ReadLine));
675 global_template->Set(String::New("load"), FunctionTemplate::New(Load));
676 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
677 global_template->Set(String::New("version"), FunctionTemplate::New(Version));
Ben Murdoch589d6972011-11-30 16:04:58 +0000678 global_template->Set(String::New("enableProfiler"),
679 FunctionTemplate::New(EnableProfiler));
680 global_template->Set(String::New("disableProfiler"),
681 FunctionTemplate::New(DisableProfiler));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000682
683 // Bind the handlers for external arrays.
684 global_template->Set(String::New("Int8Array"),
685 FunctionTemplate::New(Int8Array));
686 global_template->Set(String::New("Uint8Array"),
687 FunctionTemplate::New(Uint8Array));
688 global_template->Set(String::New("Int16Array"),
689 FunctionTemplate::New(Int16Array));
690 global_template->Set(String::New("Uint16Array"),
691 FunctionTemplate::New(Uint16Array));
692 global_template->Set(String::New("Int32Array"),
693 FunctionTemplate::New(Int32Array));
694 global_template->Set(String::New("Uint32Array"),
695 FunctionTemplate::New(Uint32Array));
696 global_template->Set(String::New("Float32Array"),
697 FunctionTemplate::New(Float32Array));
698 global_template->Set(String::New("Float64Array"),
699 FunctionTemplate::New(Float64Array));
700 global_template->Set(String::New("PixelArray"),
701 FunctionTemplate::New(PixelArray));
702
703#ifdef LIVE_OBJECT_LIST
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000704 global_template->Set(String::New("lol_is_enabled"), True());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000705#else
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000706 global_template->Set(String::New("lol_is_enabled"), False());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000707#endif
708
Ben Murdoch589d6972011-11-30 16:04:58 +0000709#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000710 Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
711 AddOSMethods(os_templ);
712 global_template->Set(String::New("os"), os_templ);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000713#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000714
715 return global_template;
Steve Blocka7e24c12009-10-30 11:49:00 +0000716}
717
718
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000719void Shell::Initialize() {
720#ifdef COMPRESS_STARTUP_DATA_BZ2
721 BZip2Decompressor startup_data_decompressor;
722 int bz2_result = startup_data_decompressor.Decompress();
723 if (bz2_result != BZ_OK) {
724 fprintf(stderr, "bzip error code: %d\n", bz2_result);
Ben Murdoch589d6972011-11-30 16:04:58 +0000725 Exit(1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000726 }
727#endif
728
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000729#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000730 Shell::counter_map_ = new CounterMap();
731 // Set up counters
732 if (i::StrLength(i::FLAG_map_counters) != 0)
733 MapCounters(i::FLAG_map_counters);
734 if (i::FLAG_dump_counters) {
735 V8::SetCounterFunction(LookupCounter);
736 V8::SetCreateHistogramFunction(CreateHistogram);
737 V8::SetAddHistogramSampleFunction(AddHistogramSample);
738 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000739#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000740 if (options.test_shell) return;
741
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000742#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000743 Locker lock;
744 HandleScope scope;
745 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
746 utility_context_ = Context::New(NULL, global_template);
747
748#ifdef ENABLE_DEBUGGER_SUPPORT
749 // Start the debugger agent if requested.
750 if (i::FLAG_debugger_agent) {
751 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
752 }
753#endif // ENABLE_DEBUGGER_SUPPORT
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000754#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000755}
756
757
758Persistent<Context> Shell::CreateEvaluationContext() {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000759#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000760 // This needs to be a critical section since this is not thread-safe
761 i::ScopedLock lock(context_mutex_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000762#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000763 // Initialize the global objects
764 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
765 Persistent<Context> context = Context::New(NULL, global_template);
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000766 ASSERT(!context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000767 Context::Scope scope(context);
768
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000769#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000770 i::JSArguments js_args = i::FLAG_js_arguments;
771 i::Handle<i::FixedArray> arguments_array =
772 FACTORY->NewFixedArray(js_args.argc());
773 for (int j = 0; j < js_args.argc(); j++) {
774 i::Handle<i::String> arg =
775 FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
776 arguments_array->set(j, *arg);
777 }
778 i::Handle<i::JSArray> arguments_jsarray =
779 FACTORY->NewJSArrayWithElements(arguments_array);
780 context->Global()->Set(String::New("arguments"),
781 Utils::ToLocal(arguments_jsarray));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000782#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000783 return context;
784}
785
786
Ben Murdoch589d6972011-11-30 16:04:58 +0000787void Shell::Exit(int exit_code) {
788 // Use _exit instead of exit to avoid races between isolate
789 // threads and static destructors.
790 fflush(stdout);
791 fflush(stderr);
792 _exit(exit_code);
793}
794
795
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000796#ifndef V8_SHARED
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000797struct CounterAndKey {
798 Counter* counter;
799 const char* key;
800};
801
802
803int CompareKeys(const void* a, const void* b) {
804 return strcmp(static_cast<const CounterAndKey*>(a)->key,
805 static_cast<const CounterAndKey*>(b)->key);
806}
807
808
Steve Blocka7e24c12009-10-30 11:49:00 +0000809void Shell::OnExit() {
Ben Murdoch589d6972011-11-30 16:04:58 +0000810 if (console != NULL) console->Close();
Steve Blocka7e24c12009-10-30 11:49:00 +0000811 if (i::FLAG_dump_counters) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000812 int number_of_counters = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000814 number_of_counters++;
815 }
816 CounterAndKey* counters = new CounterAndKey[number_of_counters];
817 int j = 0;
818 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
819 counters[j].counter = i.CurrentValue();
820 counters[j].key = i.CurrentKey();
821 }
822 qsort(counters, number_of_counters, sizeof(counters[0]), CompareKeys);
823 printf("+--------------------------------------------+-------------+\n");
824 printf("| Name | Value |\n");
825 printf("+--------------------------------------------+-------------+\n");
826 for (j = 0; j < number_of_counters; j++) {
827 Counter* counter = counters[j].counter;
828 const char* key = counters[j].key;
Steve Blocka7e24c12009-10-30 11:49:00 +0000829 if (counter->is_histogram()) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000830 printf("| c:%-40s | %11i |\n", key, counter->count());
831 printf("| t:%-40s | %11i |\n", key, counter->sample_total());
Steve Blocka7e24c12009-10-30 11:49:00 +0000832 } else {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000833 printf("| %-42s | %11i |\n", key, counter->count());
Steve Blocka7e24c12009-10-30 11:49:00 +0000834 }
835 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000836 printf("+--------------------------------------------+-------------+\n");
837 delete [] counters;
Steve Blocka7e24c12009-10-30 11:49:00 +0000838 }
839 if (counters_file_ != NULL)
840 delete counters_file_;
841}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000842#endif // V8_SHARED
843
844
845static FILE* FOpen(const char* path, const char* mode) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +0000846#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000847 FILE* result;
848 if (fopen_s(&result, path, mode) == 0) {
849 return result;
850 } else {
851 return NULL;
852 }
853#else
854 FILE* file = fopen(path, mode);
855 if (file == NULL) return NULL;
856 struct stat file_stat;
857 if (fstat(fileno(file), &file_stat) != 0) return NULL;
858 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
859 if (is_regular_file) return file;
860 fclose(file);
861 return NULL;
862#endif
863}
Steve Blocka7e24c12009-10-30 11:49:00 +0000864
865
866static char* ReadChars(const char* name, int* size_out) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000867 // Release the V8 lock while reading files.
868 v8::Unlocker unlocker(Isolate::GetCurrent());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000869 FILE* file = FOpen(name, "rb");
Steve Blocka7e24c12009-10-30 11:49:00 +0000870 if (file == NULL) return NULL;
871
872 fseek(file, 0, SEEK_END);
873 int size = ftell(file);
874 rewind(file);
875
876 char* chars = new char[size + 1];
877 chars[size] = '\0';
878 for (int i = 0; i < size;) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000879 int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
Steve Blocka7e24c12009-10-30 11:49:00 +0000880 i += read;
881 }
882 fclose(file);
883 *size_out = size;
884 return chars;
885}
886
887
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000888#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000889static char* ReadToken(char* data, char token) {
890 char* next = i::OS::StrChr(data, token);
891 if (next != NULL) {
892 *next = '\0';
893 return (next + 1);
894 }
895
896 return NULL;
897}
898
899
900static char* ReadLine(char* data) {
901 return ReadToken(data, '\n');
902}
903
904
905static char* ReadWord(char* data) {
906 return ReadToken(data, ' ');
907}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000908#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000909
910
911// Reads a file into a v8 string.
912Handle<String> Shell::ReadFile(const char* name) {
913 int size = 0;
914 char* chars = ReadChars(name, &size);
915 if (chars == NULL) return Handle<String>();
916 Handle<String> result = String::New(chars);
917 delete[] chars;
918 return result;
919}
920
921
922void Shell::RunShell() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000923 Locker locker;
924 Context::Scope context_scope(evaluation_context_);
Ben Murdoch589d6972011-11-30 16:04:58 +0000925 HandleScope outer_scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000926 Handle<String> name = String::New("(d8)");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000927#ifndef V8_SHARED
Ben Murdoch589d6972011-11-30 16:04:58 +0000928 console = LineEditor::Get();
929 printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
Ben Murdoch589d6972011-11-30 16:04:58 +0000930 console->Open();
Steve Blocka7e24c12009-10-30 11:49:00 +0000931 while (true) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000932 i::SmartArrayPointer<char> input = console->Prompt(Shell::kPrompt);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000933 if (input.is_empty()) break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000934 console->AddHistory(*input);
935 HandleScope inner_scope;
Steve Blocka7e24c12009-10-30 11:49:00 +0000936 ExecuteString(String::New(*input), name, true, true);
937 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000938#else
939 printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion());
940 static const int kBufferSize = 256;
941 while (true) {
942 char buffer[kBufferSize];
943 printf("%s", Shell::kPrompt);
944 if (fgets(buffer, kBufferSize, stdin) == NULL) break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000945 HandleScope inner_scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000946 ExecuteString(String::New(buffer), name, true, true);
947 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000948#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000949 printf("\n");
950}
951
952
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000953#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000954class ShellThread : public i::Thread {
955 public:
Ben Murdoch589d6972011-11-30 16:04:58 +0000956 // Takes ownership of the underlying char array of |files|.
957 ShellThread(int no, char* files)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000958 : Thread("d8:ShellThread"),
959 no_(no), files_(files) { }
Ben Murdoch589d6972011-11-30 16:04:58 +0000960
961 ~ShellThread() {
962 delete[] files_;
963 }
964
Steve Blocka7e24c12009-10-30 11:49:00 +0000965 virtual void Run();
966 private:
967 int no_;
Ben Murdoch589d6972011-11-30 16:04:58 +0000968 char* files_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000969};
970
971
972void ShellThread::Run() {
Ben Murdoch589d6972011-11-30 16:04:58 +0000973 char* ptr = files_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000974 while ((ptr != NULL) && (*ptr != '\0')) {
975 // For each newline-separated line.
976 char* next_line = ReadLine(ptr);
977
978 if (*ptr == '#') {
979 // Skip comment lines.
980 ptr = next_line;
981 continue;
982 }
983
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000984 // Prepare the context for this thread.
985 Locker locker;
Ben Murdoch589d6972011-11-30 16:04:58 +0000986 HandleScope outer_scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000987 Persistent<Context> thread_context = Shell::CreateEvaluationContext();
Steve Blocka7e24c12009-10-30 11:49:00 +0000988 Context::Scope context_scope(thread_context);
989
990 while ((ptr != NULL) && (*ptr != '\0')) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000991 HandleScope inner_scope;
Steve Blocka7e24c12009-10-30 11:49:00 +0000992 char* filename = ptr;
993 ptr = ReadWord(ptr);
994
995 // Skip empty strings.
996 if (strlen(filename) == 0) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000997 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000998 }
999
1000 Handle<String> str = Shell::ReadFile(filename);
1001 if (str.IsEmpty()) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001002 printf("File '%s' not found\n", filename);
1003 Shell::Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001004 }
1005
1006 Shell::ExecuteString(str, String::New(filename), false, false);
1007 }
1008
1009 thread_context.Dispose();
1010 ptr = next_line;
1011 }
1012}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001013#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001014
1015
Ben Murdoch589d6972011-11-30 16:04:58 +00001016SourceGroup::~SourceGroup() {
1017#ifndef V8_SHARED
1018 delete next_semaphore_;
1019 next_semaphore_ = NULL;
1020 delete done_semaphore_;
1021 done_semaphore_ = NULL;
1022 delete thread_;
1023 thread_ = NULL;
1024#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001025}
Steve Blocka7e24c12009-10-30 11:49:00 +00001026
Steve Blocka7e24c12009-10-30 11:49:00 +00001027
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001028void SourceGroup::Execute() {
1029 for (int i = begin_offset_; i < end_offset_; ++i) {
1030 const char* arg = argv_[i];
1031 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1032 // Execute argument given to -e option directly.
1033 HandleScope handle_scope;
1034 Handle<String> file_name = String::New("unnamed");
1035 Handle<String> source = String::New(argv_[i + 1]);
1036 if (!Shell::ExecuteString(source, file_name, false, true)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001037 Shell::Exit(1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001038 }
1039 ++i;
1040 } else if (arg[0] == '-') {
1041 // Ignore other options. They have been parsed already.
1042 } else {
1043 // Use all other arguments as names of files to load and run.
1044 HandleScope handle_scope;
1045 Handle<String> file_name = String::New(arg);
1046 Handle<String> source = ReadFile(arg);
1047 if (source.IsEmpty()) {
1048 printf("Error reading '%s'\n", arg);
Ben Murdoch589d6972011-11-30 16:04:58 +00001049 Shell::Exit(1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001050 }
1051 if (!Shell::ExecuteString(source, file_name, false, true)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001052 Shell::Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001053 }
1054 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001055 }
1056}
Steve Blocka7e24c12009-10-30 11:49:00 +00001057
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001058
1059Handle<String> SourceGroup::ReadFile(const char* name) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001060 int size;
1061 const char* chars = ReadChars(name, &size);
1062 if (chars == NULL) return Handle<String>();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001063 Handle<String> result = String::New(chars, size);
1064 delete[] chars;
1065 return result;
1066}
1067
1068
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001069#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001070i::Thread::Options SourceGroup::GetThreadOptions() {
1071 i::Thread::Options options;
1072 options.name = "IsolateThread";
1073 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1074 // which is not enough to parse the big literal expressions used in tests.
1075 // The stack size should be at least StackGuard::kLimitSize + some
1076 // OS-specific padding for thread startup code.
1077 options.stack_size = 2 << 20; // 2 Mb seems to be enough
1078 return options;
1079}
1080
1081
1082void SourceGroup::ExecuteInThread() {
1083 Isolate* isolate = Isolate::New();
1084 do {
1085 if (next_semaphore_ != NULL) next_semaphore_->Wait();
1086 {
1087 Isolate::Scope iscope(isolate);
1088 Locker lock(isolate);
1089 HandleScope scope;
1090 Persistent<Context> context = Shell::CreateEvaluationContext();
1091 {
1092 Context::Scope cscope(context);
1093 Execute();
1094 }
1095 context.Dispose();
1096 }
1097 if (done_semaphore_ != NULL) done_semaphore_->Signal();
1098 } while (!Shell::options.last_run);
1099 isolate->Dispose();
1100}
1101
1102
1103void SourceGroup::StartExecuteInThread() {
1104 if (thread_ == NULL) {
1105 thread_ = new IsolateThread(this);
1106 thread_->Start();
1107 }
1108 next_semaphore_->Signal();
1109}
1110
1111
1112void SourceGroup::WaitForThread() {
1113 if (thread_ == NULL) return;
1114 if (Shell::options.last_run) {
1115 thread_->Join();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001116 } else {
1117 done_semaphore_->Wait();
1118 }
1119}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001120#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001121
1122
1123bool Shell::SetOptions(int argc, char* argv[]) {
1124 for (int i = 0; i < argc; i++) {
1125 if (strcmp(argv[i], "--stress-opt") == 0) {
1126 options.stress_opt = true;
1127 argv[i] = NULL;
1128 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1129 options.stress_deopt = true;
1130 argv[i] = NULL;
1131 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1132 // No support for stressing if we can't use --always-opt.
1133 options.stress_opt = false;
1134 options.stress_deopt = false;
1135 } else if (strcmp(argv[i], "--shell") == 0) {
1136 options.interactive_shell = true;
1137 argv[i] = NULL;
1138 } else if (strcmp(argv[i], "--test") == 0) {
1139 options.test_shell = true;
1140 argv[i] = NULL;
1141 } else if (strcmp(argv[i], "--preemption") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001142#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001143 printf("D8 with shared library does not support multi-threading\n");
1144 return false;
1145#else
1146 options.use_preemption = true;
1147 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001148#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001149 } else if (strcmp(argv[i], "--no-preemption") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001150#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001151 printf("D8 with shared library does not support multi-threading\n");
1152 return false;
1153#else
1154 options.use_preemption = false;
1155 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001156#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001157 } else if (strcmp(argv[i], "--preemption-interval") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001158#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001159 printf("D8 with shared library does not support multi-threading\n");
1160 return false;
1161#else
1162 if (++i < argc) {
1163 argv[i-1] = NULL;
1164 char* end = NULL;
1165 options.preemption_interval = strtol(argv[i], &end, 10); // NOLINT
1166 if (options.preemption_interval <= 0
1167 || *end != '\0'
1168 || errno == ERANGE) {
1169 printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
1170 return false;
1171 }
1172 argv[i] = NULL;
1173 } else {
1174 printf("Missing value for --preemption-interval\n");
1175 return false;
1176 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001177#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001178 } else if (strcmp(argv[i], "-f") == 0) {
1179 // Ignore any -f flags for compatibility with other stand-alone
1180 // JavaScript engines.
1181 continue;
1182 } else if (strcmp(argv[i], "--isolate") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001183#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001184 printf("D8 with shared library does not support multi-threading\n");
1185 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001186#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001187 options.num_isolates++;
Ben Murdoch589d6972011-11-30 16:04:58 +00001188 } else if (strcmp(argv[i], "-p") == 0) {
1189#ifdef V8_SHARED
1190 printf("D8 with shared library does not support multi-threading\n");
1191 return false;
1192#else
1193 options.num_parallel_files++;
1194#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001195 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001196#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001197 else if (strcmp(argv[i], "--dump-counters") == 0) {
1198 printf("D8 with shared library does not include counters\n");
1199 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001200 } else if (strcmp(argv[i], "--debugger") == 0) {
1201 printf("Javascript debugger not included\n");
1202 return false;
1203 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001204#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001205 }
1206
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001207#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001208 // Run parallel threads if we are not using --isolate
Ben Murdoch589d6972011-11-30 16:04:58 +00001209 options.parallel_files = new char*[options.num_parallel_files];
1210 int parallel_files_set = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001211 for (int i = 1; i < argc; i++) {
1212 if (argv[i] == NULL) continue;
1213 if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
1214 if (options.num_isolates > 1) {
1215 printf("-p is not compatible with --isolate\n");
1216 return false;
1217 }
1218 argv[i] = NULL;
Ben Murdoch589d6972011-11-30 16:04:58 +00001219 i++;
1220 options.parallel_files[parallel_files_set] = argv[i];
1221 parallel_files_set++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001222 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001223 }
1224 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001225 if (parallel_files_set != options.num_parallel_files) {
1226 printf("-p requires a file containing a list of files as parameter\n");
1227 return false;
1228 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001229#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001230
1231 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1232
Ben Murdoch589d6972011-11-30 16:04:58 +00001233 // Set up isolated source groups.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001234 options.isolate_sources = new SourceGroup[options.num_isolates];
1235 SourceGroup* current = options.isolate_sources;
1236 current->Begin(argv, 1);
1237 for (int i = 1; i < argc; i++) {
1238 const char* str = argv[i];
1239 if (strcmp(str, "--isolate") == 0) {
1240 current->End(i);
1241 current++;
1242 current->Begin(argv, i + 1);
1243 } else if (strncmp(argv[i], "--", 2) == 0) {
1244 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
1245 }
1246 }
1247 current->End(argc);
1248
1249 return true;
1250}
1251
1252
1253int Shell::RunMain(int argc, char* argv[]) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001254#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001255 i::List<i::Thread*> threads(1);
Ben Murdoch589d6972011-11-30 16:04:58 +00001256 if (options.parallel_files != NULL) {
1257 for (int i = 0; i < options.num_parallel_files; i++) {
1258 char* files = NULL;
1259 { Locker lock(Isolate::GetCurrent());
1260 int size = 0;
1261 files = ReadChars(options.parallel_files[i], &size);
1262 }
1263 if (files == NULL) {
1264 printf("File list '%s' not found\n", options.parallel_files[i]);
1265 Exit(1);
1266 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001267 ShellThread* thread = new ShellThread(threads.length(), files);
1268 thread->Start();
1269 threads.Add(thread);
1270 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001271 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001272 for (int i = 1; i < options.num_isolates; ++i) {
1273 options.isolate_sources[i].StartExecuteInThread();
1274 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001275#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001276 { // NOLINT
1277 Locker lock;
1278 HandleScope scope;
1279 Persistent<Context> context = CreateEvaluationContext();
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001280 if (options.last_run) {
1281 // Keep using the same context in the interactive shell.
1282 evaluation_context_ = context;
1283#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
1284 // If the interactive debugger is enabled make sure to activate
1285 // it before running the files passed on the command line.
1286 if (i::FLAG_debugger) {
1287 InstallUtilityScript();
1288 }
1289#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
1290 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001291 {
1292 Context::Scope cscope(context);
1293 options.isolate_sources[0].Execute();
1294 }
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001295 if (!options.last_run) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001296 context.Dispose();
1297 }
1298
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001299#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001300 // Start preemption if threads have been created and preemption is enabled.
Ben Murdoch589d6972011-11-30 16:04:58 +00001301 if (threads.length() > 0
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001302 && options.use_preemption) {
1303 Locker::StartPreemption(options.preemption_interval);
1304 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001305#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001306 }
1307
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001308#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001309 for (int i = 1; i < options.num_isolates; ++i) {
1310 options.isolate_sources[i].WaitForThread();
1311 }
1312
Ben Murdoch589d6972011-11-30 16:04:58 +00001313 for (int i = 0; i < threads.length(); i++) {
1314 i::Thread* thread = threads[i];
1315 thread->Join();
1316 delete thread;
1317 }
1318
1319 if (threads.length() > 0 && options.use_preemption) {
1320 Locker lock;
1321 Locker::StopPreemption();
1322 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001323#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001324 return 0;
1325}
1326
1327
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001328int Shell::Main(int argc, char* argv[]) {
1329 if (!SetOptions(argc, argv)) return 1;
1330 Initialize();
1331
1332 int result = 0;
1333 if (options.stress_opt || options.stress_deopt) {
1334 Testing::SetStressRunType(
1335 options.stress_opt ? Testing::kStressTypeOpt
1336 : Testing::kStressTypeDeopt);
1337 int stress_runs = Testing::GetStressRuns();
1338 for (int i = 0; i < stress_runs && result == 0; i++) {
1339 printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
1340 Testing::PrepareStressRun(i);
1341 options.last_run = (i == stress_runs - 1);
1342 result = RunMain(argc, argv);
1343 }
1344 printf("======== Full Deoptimization =======\n");
1345 Testing::DeoptimizeAll();
1346 } else {
1347 result = RunMain(argc, argv);
1348 }
1349
1350
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001351#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001352 // Run remote debugger if requested, but never on --test
1353 if (i::FLAG_remote_debugger && !options.test_shell) {
1354 InstallUtilityScript();
1355 RunRemoteDebugger(i::FLAG_debugger_port);
1356 return 0;
1357 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001358#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001359
1360 // Run interactive shell if explicitly requested or if no script has been
1361 // executed, but never on --test
1362
1363 if (( options.interactive_shell
1364 || !options.script_executed )
1365 && !options.test_shell ) {
Ben Murdoch592a9fc2012-03-05 11:04:45 +00001366#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
1367 if (!i::FLAG_debugger) {
1368 InstallUtilityScript();
1369 }
1370#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001371 RunShell();
1372 }
1373
1374 V8::Dispose();
1375
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001376#ifndef V8_SHARED
1377 OnExit();
1378#endif // V8_SHARED
1379
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001380 return result;
1381}
1382
Steve Blocka7e24c12009-10-30 11:49:00 +00001383} // namespace v8
1384
1385
Ben Murdoch257744e2011-11-30 15:57:28 +00001386#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +00001387int main(int argc, char* argv[]) {
1388 return v8::Shell::Main(argc, argv);
1389}
Ben Murdoch257744e2011-11-30 15:57:28 +00001390#endif