blob: f1068cb42f37831d1e71216b8fe7477f7d3ff4f1 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 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#include <stdlib.h>
30#include <errno.h>
31
Steve Block44f0eee2011-05-26 01:26:41 +010032#include "v8.h"
33
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include "d8.h"
35#include "d8-debug.h"
36#include "debug.h"
37#include "api.h"
38#include "natives.h"
39#include "platform.h"
40
41
42namespace v8 {
43
44
45const char* Shell::kHistoryFileName = ".d8_history";
46const char* Shell::kPrompt = "d8> ";
47
48
49LineEditor *LineEditor::first_ = NULL;
50
51
52LineEditor::LineEditor(Type type, const char* name)
53 : type_(type),
54 name_(name),
55 next_(first_) {
56 first_ = this;
57}
58
59
60LineEditor* LineEditor::Get() {
61 LineEditor* current = first_;
62 LineEditor* best = current;
63 while (current != NULL) {
64 if (current->type_ > best->type_)
65 best = current;
66 current = current->next_;
67 }
68 return best;
69}
70
71
72class DumbLineEditor: public LineEditor {
73 public:
74 DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
75 virtual i::SmartPointer<char> Prompt(const char* prompt);
76};
77
78
79static DumbLineEditor dumb_line_editor;
80
81
82i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) {
83 static const int kBufferSize = 256;
84 char buffer[kBufferSize];
85 printf("%s", prompt);
86 char* str = fgets(buffer, kBufferSize, stdin);
87 return i::SmartPointer<char>(str ? i::StrDup(str) : str);
88}
89
90
91CounterMap* Shell::counter_map_;
92i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
93CounterCollection Shell::local_counters_;
94CounterCollection* Shell::counters_ = &local_counters_;
95Persistent<Context> Shell::utility_context_;
96Persistent<Context> Shell::evaluation_context_;
97
98
99bool CounterMap::Match(void* key1, void* key2) {
100 const char* name1 = reinterpret_cast<const char*>(key1);
101 const char* name2 = reinterpret_cast<const char*>(key2);
102 return strcmp(name1, name2) == 0;
103}
104
105
106// Converts a V8 value to a C string.
Steve Block6ded16b2010-05-10 14:33:55 +0100107const char* Shell::ToCString(const v8::String::Utf8Value& value) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000108 return *value ? *value : "<string conversion failed>";
109}
110
111
112// Executes a string within the current v8 context.
113bool Shell::ExecuteString(Handle<String> source,
114 Handle<Value> name,
115 bool print_result,
116 bool report_exceptions) {
117 HandleScope handle_scope;
118 TryCatch try_catch;
119 if (i::FLAG_debugger) {
120 // When debugging make exceptions appear to be uncaught.
121 try_catch.SetVerbose(true);
122 }
123 Handle<Script> script = Script::Compile(source, name);
124 if (script.IsEmpty()) {
125 // Print errors that happened during compilation.
126 if (report_exceptions && !i::FLAG_debugger)
127 ReportException(&try_catch);
128 return false;
129 } else {
130 Handle<Value> result = script->Run();
131 if (result.IsEmpty()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100132 ASSERT(try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 // Print errors that happened during execution.
134 if (report_exceptions && !i::FLAG_debugger)
135 ReportException(&try_catch);
136 return false;
137 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100138 ASSERT(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000139 if (print_result && !result->IsUndefined()) {
140 // If all went well and the result wasn't undefined then print
141 // the returned value.
142 v8::String::Utf8Value str(result);
143 const char* cstr = ToCString(str);
144 printf("%s\n", cstr);
145 }
146 return true;
147 }
148 }
149}
150
151
152Handle<Value> Shell::Print(const Arguments& args) {
153 Handle<Value> val = Write(args);
154 printf("\n");
155 return val;
156}
157
158
159Handle<Value> Shell::Write(const Arguments& args) {
160 for (int i = 0; i < args.Length(); i++) {
161 HandleScope handle_scope;
162 if (i != 0) {
163 printf(" ");
164 }
165 v8::String::Utf8Value str(args[i]);
Steve Blockd0582a62009-12-15 09:54:21 +0000166 int n = fwrite(*str, sizeof(**str), str.length(), stdout);
167 if (n != str.length()) {
168 printf("Error in fwrite\n");
169 exit(1);
170 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000171 }
172 return Undefined();
173}
174
175
176Handle<Value> Shell::Read(const Arguments& args) {
177 String::Utf8Value file(args[0]);
178 if (*file == NULL) {
179 return ThrowException(String::New("Error loading file"));
180 }
181 Handle<String> source = ReadFile(*file);
182 if (source.IsEmpty()) {
183 return ThrowException(String::New("Error loading file"));
184 }
185 return source;
186}
187
188
189Handle<Value> Shell::ReadLine(const Arguments& args) {
190 i::SmartPointer<char> line(i::ReadLine(""));
191 if (*line == NULL) {
192 return Null();
193 }
194 size_t len = strlen(*line);
195 if (len > 0 && line[len - 1] == '\n') {
196 --len;
197 }
198 return String::New(*line, len);
199}
200
201
202Handle<Value> Shell::Load(const Arguments& args) {
203 for (int i = 0; i < args.Length(); i++) {
204 HandleScope handle_scope;
205 String::Utf8Value file(args[i]);
206 if (*file == NULL) {
207 return ThrowException(String::New("Error loading file"));
208 }
209 Handle<String> source = ReadFile(*file);
210 if (source.IsEmpty()) {
211 return ThrowException(String::New("Error loading file"));
212 }
213 if (!ExecuteString(source, String::New(*file), false, false)) {
Steve Blockd0582a62009-12-15 09:54:21 +0000214 return ThrowException(String::New("Error executing file"));
Steve Blocka7e24c12009-10-30 11:49:00 +0000215 }
216 }
217 return Undefined();
218}
219
220
221Handle<Value> Shell::Yield(const Arguments& args) {
222 v8::Unlocker unlocker;
223 return Undefined();
224}
225
226
227Handle<Value> Shell::Quit(const Arguments& args) {
228 int exit_code = args[0]->Int32Value();
229 OnExit();
230 exit(exit_code);
231 return Undefined();
232}
233
234
235Handle<Value> Shell::Version(const Arguments& args) {
236 return String::New(V8::GetVersion());
237}
238
239
240void Shell::ReportException(v8::TryCatch* try_catch) {
241 HandleScope handle_scope;
242 v8::String::Utf8Value exception(try_catch->Exception());
243 const char* exception_string = ToCString(exception);
244 Handle<Message> message = try_catch->Message();
245 if (message.IsEmpty()) {
246 // V8 didn't provide any extra information about this error; just
247 // print the exception.
248 printf("%s\n", exception_string);
249 } else {
250 // Print (filename):(line number): (message).
251 v8::String::Utf8Value filename(message->GetScriptResourceName());
252 const char* filename_string = ToCString(filename);
253 int linenum = message->GetLineNumber();
254 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
255 // Print line of source code.
256 v8::String::Utf8Value sourceline(message->GetSourceLine());
257 const char* sourceline_string = ToCString(sourceline);
258 printf("%s\n", sourceline_string);
259 // Print wavy underline (GetUnderline is deprecated).
260 int start = message->GetStartColumn();
261 for (int i = 0; i < start; i++) {
262 printf(" ");
263 }
264 int end = message->GetEndColumn();
265 for (int i = start; i < end; i++) {
266 printf("^");
267 }
268 printf("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000269 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
270 if (stack_trace.length() > 0) {
271 const char* stack_trace_string = ToCString(stack_trace);
272 printf("%s\n", stack_trace_string);
273 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000274 }
275}
276
277
278Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
279 HandleScope handle_scope;
280 Context::Scope context_scope(utility_context_);
281 Handle<Object> global = utility_context_->Global();
282 Handle<Value> fun = global->Get(String::New("GetCompletions"));
283 static const int kArgc = 3;
284 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
285 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
286 return handle_scope.Close(Handle<Array>::Cast(val));
287}
288
289
290#ifdef ENABLE_DEBUGGER_SUPPORT
291Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
292 Context::Scope context_scope(utility_context_);
293 Handle<Object> global = utility_context_->Global();
294 Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
295 static const int kArgc = 1;
296 Handle<Value> argv[kArgc] = { message };
297 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
298 return Handle<Object>::Cast(val);
299}
300
301
302Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
303 Context::Scope context_scope(utility_context_);
304 Handle<Object> global = utility_context_->Global();
305 Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
306 static const int kArgc = 1;
307 Handle<Value> argv[kArgc] = { command };
308 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
309 return val;
310}
311#endif
312
313
314int32_t* Counter::Bind(const char* name, bool is_histogram) {
315 int i;
316 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
317 name_[i] = static_cast<char>(name[i]);
318 name_[i] = '\0';
319 is_histogram_ = is_histogram;
320 return ptr();
321}
322
323
324void Counter::AddSample(int32_t sample) {
325 count_++;
326 sample_total_ += sample;
327}
328
329
330CounterCollection::CounterCollection() {
331 magic_number_ = 0xDEADFACE;
332 max_counters_ = kMaxCounters;
333 max_name_size_ = Counter::kMaxNameSize;
334 counters_in_use_ = 0;
335}
336
337
338Counter* CounterCollection::GetNextCounter() {
339 if (counters_in_use_ == kMaxCounters) return NULL;
340 return &counters_[counters_in_use_++];
341}
342
343
344void Shell::MapCounters(const char* name) {
345 counters_file_ = i::OS::MemoryMappedFile::create(name,
346 sizeof(CounterCollection), &local_counters_);
347 void* memory = (counters_file_ == NULL) ?
348 NULL : counters_file_->memory();
349 if (memory == NULL) {
350 printf("Could not map counters file %s\n", name);
351 exit(1);
352 }
353 counters_ = static_cast<CounterCollection*>(memory);
354 V8::SetCounterFunction(LookupCounter);
355 V8::SetCreateHistogramFunction(CreateHistogram);
356 V8::SetAddHistogramSampleFunction(AddHistogramSample);
357}
358
359
360int CounterMap::Hash(const char* name) {
361 int h = 0;
362 int c;
363 while ((c = *name++) != 0) {
364 h += h << 5;
365 h += c;
366 }
367 return h;
368}
369
370
371Counter* Shell::GetCounter(const char* name, bool is_histogram) {
372 Counter* counter = counter_map_->Lookup(name);
373
374 if (counter == NULL) {
375 counter = counters_->GetNextCounter();
376 if (counter != NULL) {
377 counter_map_->Set(name, counter);
378 counter->Bind(name, is_histogram);
379 }
380 } else {
381 ASSERT(counter->is_histogram() == is_histogram);
382 }
383 return counter;
384}
385
386
387int* Shell::LookupCounter(const char* name) {
388 Counter* counter = GetCounter(name, false);
389
390 if (counter != NULL) {
391 return counter->ptr();
392 } else {
393 return NULL;
394 }
395}
396
397
398void* Shell::CreateHistogram(const char* name,
399 int min,
400 int max,
401 size_t buckets) {
402 return GetCounter(name, true);
403}
404
405
406void Shell::AddHistogramSample(void* histogram, int sample) {
407 Counter* counter = reinterpret_cast<Counter*>(histogram);
408 counter->AddSample(sample);
409}
410
411
412void Shell::Initialize() {
413 Shell::counter_map_ = new CounterMap();
414 // Set up counters
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100415 if (i::StrLength(i::FLAG_map_counters) != 0)
Steve Blocka7e24c12009-10-30 11:49:00 +0000416 MapCounters(i::FLAG_map_counters);
417 if (i::FLAG_dump_counters) {
418 V8::SetCounterFunction(LookupCounter);
419 V8::SetCreateHistogramFunction(CreateHistogram);
420 V8::SetAddHistogramSampleFunction(AddHistogramSample);
421 }
422
423 // Initialize the global objects
424 HandleScope scope;
425 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
426 global_template->Set(String::New("print"), FunctionTemplate::New(Print));
427 global_template->Set(String::New("write"), FunctionTemplate::New(Write));
428 global_template->Set(String::New("read"), FunctionTemplate::New(Read));
429 global_template->Set(String::New("readline"),
430 FunctionTemplate::New(ReadLine));
431 global_template->Set(String::New("load"), FunctionTemplate::New(Load));
432 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
433 global_template->Set(String::New("version"), FunctionTemplate::New(Version));
434
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100435#ifdef LIVE_OBJECT_LIST
436 global_template->Set(String::New("lol_is_enabled"), Boolean::New(true));
437#else
438 global_template->Set(String::New("lol_is_enabled"), Boolean::New(false));
439#endif
440
Steve Blocka7e24c12009-10-30 11:49:00 +0000441 Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
442 AddOSMethods(os_templ);
443 global_template->Set(String::New("os"), os_templ);
444
445 utility_context_ = Context::New(NULL, global_template);
446 utility_context_->SetSecurityToken(Undefined());
447 Context::Scope utility_scope(utility_context_);
448
449 i::JSArguments js_args = i::FLAG_js_arguments;
450 i::Handle<i::FixedArray> arguments_array =
Steve Block44f0eee2011-05-26 01:26:41 +0100451 FACTORY->NewFixedArray(js_args.argc());
Steve Blocka7e24c12009-10-30 11:49:00 +0000452 for (int j = 0; j < js_args.argc(); j++) {
453 i::Handle<i::String> arg =
Steve Block44f0eee2011-05-26 01:26:41 +0100454 FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
Steve Blocka7e24c12009-10-30 11:49:00 +0000455 arguments_array->set(j, *arg);
456 }
457 i::Handle<i::JSArray> arguments_jsarray =
Steve Block44f0eee2011-05-26 01:26:41 +0100458 FACTORY->NewJSArrayWithElements(arguments_array);
Steve Blocka7e24c12009-10-30 11:49:00 +0000459 global_template->Set(String::New("arguments"),
460 Utils::ToLocal(arguments_jsarray));
461
462#ifdef ENABLE_DEBUGGER_SUPPORT
463 // Install the debugger object in the utility scope
Steve Block44f0eee2011-05-26 01:26:41 +0100464 i::Debug* debug = i::Isolate::Current()->debug();
465 debug->Load();
466 i::Handle<i::JSObject> js_debug
467 = i::Handle<i::JSObject>(debug->debug_context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +0000468 utility_context_->Global()->Set(String::New("$debug"),
Steve Block44f0eee2011-05-26 01:26:41 +0100469 Utils::ToLocal(js_debug));
Steve Blocka7e24c12009-10-30 11:49:00 +0000470#endif
471
472 // Run the d8 shell utility script in the utility context
473 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
474 i::Vector<const char> shell_source
475 = i::NativesCollection<i::D8>::GetScriptSource(source_index);
476 i::Vector<const char> shell_source_name
477 = i::NativesCollection<i::D8>::GetScriptName(source_index);
478 Handle<String> source = String::New(shell_source.start(),
479 shell_source.length());
480 Handle<String> name = String::New(shell_source_name.start(),
481 shell_source_name.length());
482 Handle<Script> script = Script::Compile(source, name);
483 script->Run();
484
485 // Mark the d8 shell script as native to avoid it showing up as normal source
486 // in the debugger.
Steve Block6ded16b2010-05-10 14:33:55 +0100487 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
488 i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
489 ? i::Handle<i::Script>(i::Script::cast(
490 i::JSFunction::cast(*compiled_script)->shared()->script()))
491 : i::Handle<i::Script>(i::Script::cast(
492 i::SharedFunctionInfo::cast(*compiled_script)->script()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000493 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
494
495 // Create the evaluation context
496 evaluation_context_ = Context::New(NULL, global_template);
497 evaluation_context_->SetSecurityToken(Undefined());
498
499#ifdef ENABLE_DEBUGGER_SUPPORT
500 // Set the security token of the debug context to allow access.
Steve Block44f0eee2011-05-26 01:26:41 +0100501 debug->debug_context()->set_security_token(HEAP->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000502
503 // Start the debugger agent if requested.
504 if (i::FLAG_debugger_agent) {
Iain Merrick9ac36c92010-09-13 15:29:50 +0100505 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000506 }
507
508 // Start the in-process debugger if requested.
509 if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
510 v8::Debug::SetDebugEventListener(HandleDebugEvent);
511 }
512#endif
513}
514
515
516void Shell::OnExit() {
517 if (i::FLAG_dump_counters) {
518 ::printf("+----------------------------------------+-------------+\n");
519 ::printf("| Name | Value |\n");
520 ::printf("+----------------------------------------+-------------+\n");
521 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
522 Counter* counter = i.CurrentValue();
523 if (counter->is_histogram()) {
524 ::printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
525 ::printf("| t:%-36s | %11i |\n",
526 i.CurrentKey(),
527 counter->sample_total());
528 } else {
529 ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
530 }
531 }
532 ::printf("+----------------------------------------+-------------+\n");
533 }
534 if (counters_file_ != NULL)
535 delete counters_file_;
536}
537
538
539static char* ReadChars(const char* name, int* size_out) {
540 v8::Unlocker unlocker; // Release the V8 lock while reading files.
541 FILE* file = i::OS::FOpen(name, "rb");
542 if (file == NULL) return NULL;
543
544 fseek(file, 0, SEEK_END);
545 int size = ftell(file);
546 rewind(file);
547
548 char* chars = new char[size + 1];
549 chars[size] = '\0';
550 for (int i = 0; i < size;) {
551 int read = fread(&chars[i], 1, size - i, file);
552 i += read;
553 }
554 fclose(file);
555 *size_out = size;
556 return chars;
557}
558
559
560static char* ReadToken(char* data, char token) {
561 char* next = i::OS::StrChr(data, token);
562 if (next != NULL) {
563 *next = '\0';
564 return (next + 1);
565 }
566
567 return NULL;
568}
569
570
571static char* ReadLine(char* data) {
572 return ReadToken(data, '\n');
573}
574
575
576static char* ReadWord(char* data) {
577 return ReadToken(data, ' ');
578}
579
580
581// Reads a file into a v8 string.
582Handle<String> Shell::ReadFile(const char* name) {
583 int size = 0;
584 char* chars = ReadChars(name, &size);
585 if (chars == NULL) return Handle<String>();
586 Handle<String> result = String::New(chars);
587 delete[] chars;
588 return result;
589}
590
591
592void Shell::RunShell() {
593 LineEditor* editor = LineEditor::Get();
594 printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100595 if (i::FLAG_debugger) {
596 printf("JavaScript debugger enabled\n");
597 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000598 editor->Open();
599 while (true) {
600 Locker locker;
601 HandleScope handle_scope;
602 Context::Scope context_scope(evaluation_context_);
603 i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
604 if (input.is_empty())
605 break;
606 editor->AddHistory(*input);
607 Handle<String> name = String::New("(d8)");
608 ExecuteString(String::New(*input), name, true, true);
609 }
610 editor->Close();
611 printf("\n");
612}
613
614
615class ShellThread : public i::Thread {
616 public:
Steve Block44f0eee2011-05-26 01:26:41 +0100617 ShellThread(i::Isolate* isolate, int no, i::Vector<const char> files)
618 : Thread(isolate, "d8:ShellThread"),
Steve Block9fac8402011-05-12 15:51:54 +0100619 no_(no), files_(files) { }
Steve Blocka7e24c12009-10-30 11:49:00 +0000620 virtual void Run();
621 private:
622 int no_;
623 i::Vector<const char> files_;
624};
625
626
627void ShellThread::Run() {
628 // Prepare the context for this thread.
629 Locker locker;
630 HandleScope scope;
631 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
632 global_template->Set(String::New("print"),
633 FunctionTemplate::New(Shell::Print));
634 global_template->Set(String::New("write"),
635 FunctionTemplate::New(Shell::Write));
636 global_template->Set(String::New("read"),
637 FunctionTemplate::New(Shell::Read));
638 global_template->Set(String::New("readline"),
639 FunctionTemplate::New(Shell::ReadLine));
640 global_template->Set(String::New("load"),
641 FunctionTemplate::New(Shell::Load));
642 global_template->Set(String::New("yield"),
643 FunctionTemplate::New(Shell::Yield));
644 global_template->Set(String::New("version"),
645 FunctionTemplate::New(Shell::Version));
646
647 char* ptr = const_cast<char*>(files_.start());
648 while ((ptr != NULL) && (*ptr != '\0')) {
649 // For each newline-separated line.
650 char* next_line = ReadLine(ptr);
651
652 if (*ptr == '#') {
653 // Skip comment lines.
654 ptr = next_line;
655 continue;
656 }
657
658 Persistent<Context> thread_context = Context::New(NULL, global_template);
659 thread_context->SetSecurityToken(Undefined());
660 Context::Scope context_scope(thread_context);
661
662 while ((ptr != NULL) && (*ptr != '\0')) {
663 char* filename = ptr;
664 ptr = ReadWord(ptr);
665
666 // Skip empty strings.
667 if (strlen(filename) == 0) {
668 break;
669 }
670
671 Handle<String> str = Shell::ReadFile(filename);
672 if (str.IsEmpty()) {
673 printf("WARNING: %s not found\n", filename);
674 break;
675 }
676
677 Shell::ExecuteString(str, String::New(filename), false, false);
678 }
679
680 thread_context.Dispose();
681 ptr = next_line;
682 }
683}
684
685
686int Shell::Main(int argc, char* argv[]) {
687 i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
688 if (i::FLAG_help) {
689 return 1;
690 }
691 Initialize();
692 bool run_shell = (argc == 1);
693
694 // Default use preemption if threads are created.
695 bool use_preemption = true;
696
697 // Default to use lowest possible thread preemption interval to test as many
698 // edgecases as possible.
699 int preemption_interval = 1;
700
701 i::List<i::Thread*> threads(1);
702
703 {
704 // Acquire the V8 lock once initialization has finished. Since the thread
705 // below may spawn new threads accessing V8 holding the V8 lock here is
706 // mandatory.
707 Locker locker;
708 Context::Scope context_scope(evaluation_context_);
709 for (int i = 1; i < argc; i++) {
710 char* str = argv[i];
711 if (strcmp(str, "--shell") == 0) {
712 run_shell = true;
713 } else if (strcmp(str, "--preemption") == 0) {
714 use_preemption = true;
715 } else if (strcmp(str, "--no-preemption") == 0) {
716 use_preemption = false;
717 } else if (strcmp(str, "--preemption-interval") == 0) {
718 if (i + 1 < argc) {
719 char* end = NULL;
720 preemption_interval = strtol(argv[++i], &end, 10); // NOLINT
721 if (preemption_interval <= 0 || *end != '\0' || errno == ERANGE) {
722 printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
723 return 1;
724 }
725 } else {
726 printf("Missing value for --preemption-interval\n");
727 return 1;
728 }
729 } else if (strcmp(str, "-f") == 0) {
730 // Ignore any -f flags for compatibility with other stand-alone
731 // JavaScript engines.
732 continue;
733 } else if (strncmp(str, "--", 2) == 0) {
734 printf("Warning: unknown flag %s.\nTry --help for options\n", str);
735 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
736 // Execute argument given to -e option directly.
737 v8::HandleScope handle_scope;
738 v8::Handle<v8::String> file_name = v8::String::New("unnamed");
739 v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
740 if (!ExecuteString(source, file_name, false, true)) {
741 OnExit();
742 return 1;
743 }
744 i++;
745 } else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
746 int size = 0;
747 const char* files = ReadChars(argv[++i], &size);
748 if (files == NULL) return 1;
749 ShellThread* thread =
Steve Block44f0eee2011-05-26 01:26:41 +0100750 new ShellThread(i::Isolate::Current(),
751 threads.length(),
Steve Blocka7e24c12009-10-30 11:49:00 +0000752 i::Vector<const char>(files, size));
753 thread->Start();
754 threads.Add(thread);
755 } else {
756 // Use all other arguments as names of files to load and run.
757 HandleScope handle_scope;
758 Handle<String> file_name = v8::String::New(str);
759 Handle<String> source = ReadFile(str);
760 if (source.IsEmpty()) {
761 printf("Error reading '%s'\n", str);
762 return 1;
763 }
764 if (!ExecuteString(source, file_name, false, true)) {
765 OnExit();
766 return 1;
767 }
768 }
769 }
770
771 // Start preemption if threads have been created and preemption is enabled.
772 if (threads.length() > 0 && use_preemption) {
773 Locker::StartPreemption(preemption_interval);
774 }
775
776#ifdef ENABLE_DEBUGGER_SUPPORT
777 // Run the remote debugger if requested.
778 if (i::FLAG_remote_debugger) {
779 RunRemoteDebugger(i::FLAG_debugger_port);
780 return 0;
781 }
782#endif
783 }
784 if (run_shell)
785 RunShell();
786 for (int i = 0; i < threads.length(); i++) {
787 i::Thread* thread = threads[i];
788 thread->Join();
789 delete thread;
790 }
791 OnExit();
792 return 0;
793}
794
795
796} // namespace v8
797
798
Ben Murdoch257744e2011-11-30 15:57:28 +0000799#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +0000800int main(int argc, char* argv[]) {
801 return v8::Shell::Main(argc, argv);
802}
Ben Murdoch257744e2011-11-30 15:57:28 +0000803#endif