blob: ee845ee2cd42a060a609a5d73b4fe5b625a4f502 [file] [log] [blame]
ager@chromium.org41826e72009-03-30 13:30:57 +00001// Copyright 2009 the V8 project authors. All rights reserved.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +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
ager@chromium.orga74f0da2008-12-03 16:05:52 +000029#include <stdlib.h>
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000030#include <errno.h>
ager@chromium.orga74f0da2008-12-03 16:05:52 +000031
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000032#include "d8.h"
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000033#include "d8-debug.h"
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000034#include "debug.h"
35#include "api.h"
36#include "natives.h"
ager@chromium.orgddb913d2009-01-27 10:01:48 +000037#include "platform.h"
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000038
39
40namespace v8 {
41
42
43const char* Shell::kHistoryFileName = ".d8_history";
44const char* Shell::kPrompt = "d8> ";
45
46
47LineEditor *LineEditor::first_ = NULL;
48
49
50LineEditor::LineEditor(Type type, const char* name)
51 : type_(type),
52 name_(name),
53 next_(first_) {
54 first_ = this;
55}
56
57
58LineEditor* LineEditor::Get() {
59 LineEditor* current = first_;
60 LineEditor* best = current;
61 while (current != NULL) {
62 if (current->type_ > best->type_)
63 best = current;
64 current = current->next_;
65 }
66 return best;
67}
68
69
70class DumbLineEditor: public LineEditor {
71 public:
72 DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
73 virtual i::SmartPointer<char> Prompt(const char* prompt);
74};
75
76
77static DumbLineEditor dumb_line_editor;
78
79
80i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) {
81 static const int kBufferSize = 256;
82 char buffer[kBufferSize];
83 printf("%s", prompt);
84 char* str = fgets(buffer, kBufferSize, stdin);
ager@chromium.orga74f0da2008-12-03 16:05:52 +000085 return i::SmartPointer<char>(str ? i::StrDup(str) : str);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000086}
87
88
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +000089CounterMap* Shell::counter_map_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +000090i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
91CounterCollection Shell::local_counters_;
92CounterCollection* Shell::counters_ = &local_counters_;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000093Persistent<Context> Shell::utility_context_;
94Persistent<Context> Shell::evaluation_context_;
95
96
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +000097bool CounterMap::Match(void* key1, void* key2) {
98 const char* name1 = reinterpret_cast<const char*>(key1);
99 const char* name2 = reinterpret_cast<const char*>(key2);
100 return strcmp(name1, name2) == 0;
101}
102
103
iposva@chromium.org245aa852009-02-10 00:49:54 +0000104// Converts a V8 value to a C string.
105const char* ToCString(const v8::String::Utf8Value& value) {
106 return *value ? *value : "<string conversion failed>";
107}
108
109
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000110// Executes a string within the current v8 context.
111bool Shell::ExecuteString(Handle<String> source,
112 Handle<Value> name,
113 bool print_result,
114 bool report_exceptions) {
115 HandleScope handle_scope;
116 TryCatch try_catch;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000117 if (i::FLAG_debugger) {
118 // When debugging make exceptions appear to be uncaught.
119 try_catch.SetVerbose(true);
120 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000121 Handle<Script> script = Script::Compile(source, name);
122 if (script.IsEmpty()) {
123 // Print errors that happened during compilation.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000124 if (report_exceptions && !i::FLAG_debugger)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000125 ReportException(&try_catch);
126 return false;
127 } else {
128 Handle<Value> result = script->Run();
129 if (result.IsEmpty()) {
130 // Print errors that happened during execution.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000131 if (report_exceptions && !i::FLAG_debugger)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000132 ReportException(&try_catch);
133 return false;
134 } else {
135 if (print_result && !result->IsUndefined()) {
136 // If all went well and the result wasn't undefined then print
137 // the returned value.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000138 v8::String::Utf8Value str(result);
139 const char* cstr = ToCString(str);
140 printf("%s\n", cstr);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000141 }
142 return true;
143 }
144 }
145}
146
147
148Handle<Value> Shell::Print(const Arguments& args) {
149 bool first = true;
150 for (int i = 0; i < args.Length(); i++) {
151 HandleScope handle_scope;
152 if (first) {
153 first = false;
154 } else {
155 printf(" ");
156 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000157 v8::String::Utf8Value str(args[i]);
158 const char* cstr = ToCString(str);
159 printf("%s", cstr);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000160 }
161 printf("\n");
162 return Undefined();
163}
164
165
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000166Handle<Value> Shell::Read(const Arguments& args) {
167 if (args.Length() != 1) {
168 return ThrowException(String::New("Bad parameters"));
169 }
170 String::Utf8Value file(args[0]);
171 if (*file == NULL) {
172 return ThrowException(String::New("Error loading file"));
173 }
174 Handle<String> source = ReadFile(*file);
175 if (source.IsEmpty()) {
176 return ThrowException(String::New("Error loading file"));
177 }
178 return source;
179}
180
181
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000182Handle<Value> Shell::Load(const Arguments& args) {
183 for (int i = 0; i < args.Length(); i++) {
184 HandleScope handle_scope;
185 String::Utf8Value file(args[i]);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000186 if (*file == NULL) {
187 return ThrowException(String::New("Error loading file"));
188 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000189 Handle<String> source = ReadFile(*file);
190 if (source.IsEmpty()) {
191 return ThrowException(String::New("Error loading file"));
192 }
193 if (!ExecuteString(source, String::New(*file), false, false)) {
194 return ThrowException(String::New("Error executing file"));
195 }
196 }
197 return Undefined();
198}
199
200
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000201Handle<Value> Shell::Yield(const Arguments& args) {
202 v8::Unlocker unlocker;
203 return Undefined();
204}
205
206
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000207Handle<Value> Shell::Quit(const Arguments& args) {
208 int exit_code = args[0]->Int32Value();
209 OnExit();
210 exit(exit_code);
211 return Undefined();
212}
213
214
215Handle<Value> Shell::Version(const Arguments& args) {
216 return String::New(V8::GetVersion());
217}
218
219
220void Shell::ReportException(v8::TryCatch* try_catch) {
221 HandleScope handle_scope;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000222 v8::String::Utf8Value exception(try_catch->Exception());
223 const char* exception_string = ToCString(exception);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000224 Handle<Message> message = try_catch->Message();
225 if (message.IsEmpty()) {
226 // V8 didn't provide any extra information about this error; just
227 // print the exception.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000228 printf("%s\n", exception_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000229 } else {
230 // Print (filename):(line number): (message).
iposva@chromium.org245aa852009-02-10 00:49:54 +0000231 v8::String::Utf8Value filename(message->GetScriptResourceName());
232 const char* filename_string = ToCString(filename);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000233 int linenum = message->GetLineNumber();
iposva@chromium.org245aa852009-02-10 00:49:54 +0000234 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000235 // Print line of source code.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000236 v8::String::Utf8Value sourceline(message->GetSourceLine());
237 const char* sourceline_string = ToCString(sourceline);
238 printf("%s\n", sourceline_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000239 // Print wavy underline (GetUnderline is deprecated).
240 int start = message->GetStartColumn();
241 for (int i = 0; i < start; i++) {
242 printf(" ");
243 }
244 int end = message->GetEndColumn();
245 for (int i = start; i < end; i++) {
246 printf("^");
247 }
248 printf("\n");
249 }
250}
251
252
253Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
254 HandleScope handle_scope;
255 Context::Scope context_scope(utility_context_);
256 Handle<Object> global = utility_context_->Global();
257 Handle<Value> fun = global->Get(String::New("GetCompletions"));
258 static const int kArgc = 3;
259 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
260 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
261 return handle_scope.Close(Handle<Array>::Cast(val));
262}
263
264
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000265#ifdef ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000266Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000267 Context::Scope context_scope(utility_context_);
268 Handle<Object> global = utility_context_->Global();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000269 Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000270 static const int kArgc = 1;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000271 Handle<Value> argv[kArgc] = { message };
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000272 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000273 return Handle<Object>::Cast(val);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000274}
275
276
277Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
278 Context::Scope context_scope(utility_context_);
279 Handle<Object> global = utility_context_->Global();
280 Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
281 static const int kArgc = 1;
282 Handle<Value> argv[kArgc] = { command };
283 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
284 return val;
285}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000286#endif
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000287
288
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000289int32_t* Counter::Bind(const char* name, bool is_histogram) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000290 int i;
291 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
292 name_[i] = static_cast<char>(name[i]);
293 name_[i] = '\0';
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000294 is_histogram_ = is_histogram;
295 return ptr();
296}
297
298
299void Counter::AddSample(int32_t sample) {
300 count_++;
301 sample_total_ += sample;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000302}
303
304
305CounterCollection::CounterCollection() {
306 magic_number_ = 0xDEADFACE;
307 max_counters_ = kMaxCounters;
308 max_name_size_ = Counter::kMaxNameSize;
309 counters_in_use_ = 0;
310}
311
312
313Counter* CounterCollection::GetNextCounter() {
314 if (counters_in_use_ == kMaxCounters) return NULL;
315 return &counters_[counters_in_use_++];
316}
317
318
319void Shell::MapCounters(const char* name) {
320 counters_file_ = i::OS::MemoryMappedFile::create(name,
321 sizeof(CounterCollection), &local_counters_);
322 void* memory = (counters_file_ == NULL) ?
323 NULL : counters_file_->memory();
324 if (memory == NULL) {
325 printf("Could not map counters file %s\n", name);
326 exit(1);
327 }
328 counters_ = static_cast<CounterCollection*>(memory);
329 V8::SetCounterFunction(LookupCounter);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000330 V8::SetCreateHistogramFunction(CreateHistogram);
331 V8::SetAddHistogramSampleFunction(AddHistogramSample);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000332}
333
334
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000335int CounterMap::Hash(const char* name) {
336 int h = 0;
337 int c;
338 while ((c = *name++) != 0) {
339 h += h << 5;
340 h += c;
341 }
342 return h;
343}
344
345
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000346Counter* Shell::GetCounter(const char* name, bool is_histogram) {
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000347 Counter* counter = counter_map_->Lookup(name);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000348
349 if (counter == NULL) {
350 counter = counters_->GetNextCounter();
351 if (counter != NULL) {
352 counter_map_->Set(name, counter);
353 counter->Bind(name, is_histogram);
354 }
355 } else {
356 ASSERT(counter->is_histogram() == is_histogram);
357 }
358 return counter;
359}
360
361
362int* Shell::LookupCounter(const char* name) {
363 Counter* counter = GetCounter(name, false);
364
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000365 if (counter != NULL) {
366 return counter->ptr();
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000367 } else {
368 return NULL;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000369 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000370}
371
372
373void* Shell::CreateHistogram(const char* name,
374 int min,
375 int max,
376 size_t buckets) {
377 return GetCounter(name, true);
378}
379
380
381void Shell::AddHistogramSample(void* histogram, int sample) {
382 Counter* counter = reinterpret_cast<Counter*>(histogram);
383 counter->AddSample(sample);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000384}
385
386
387void Shell::Initialize() {
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000388 Shell::counter_map_ = new CounterMap();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000389 // Set up counters
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000390 if (i::FLAG_map_counters != NULL)
391 MapCounters(i::FLAG_map_counters);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000392 if (i::FLAG_dump_counters) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000393 V8::SetCounterFunction(LookupCounter);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000394 V8::SetCreateHistogramFunction(CreateHistogram);
395 V8::SetAddHistogramSampleFunction(AddHistogramSample);
396 }
397
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000398 // Initialize the global objects
399 HandleScope scope;
400 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
401 global_template->Set(String::New("print"), FunctionTemplate::New(Print));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000402 global_template->Set(String::New("read"), FunctionTemplate::New(Read));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000403 global_template->Set(String::New("load"), FunctionTemplate::New(Load));
404 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
405 global_template->Set(String::New("version"), FunctionTemplate::New(Version));
ager@chromium.org71daaf62009-04-01 07:22:49 +0000406
407 Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
408 AddOSMethods(os_templ);
409 global_template->Set(String::New("os"), os_templ);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000410
411 utility_context_ = Context::New(NULL, global_template);
412 utility_context_->SetSecurityToken(Undefined());
413 Context::Scope utility_scope(utility_context_);
414
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000415 i::JSArguments js_args = i::FLAG_js_arguments;
416 i::Handle<i::FixedArray> arguments_array =
417 i::Factory::NewFixedArray(js_args.argc());
418 for (int j = 0; j < js_args.argc(); j++) {
419 i::Handle<i::String> arg =
420 i::Factory::NewStringFromUtf8(i::CStrVector(js_args[j]));
421 arguments_array->set(j, *arg);
422 }
423 i::Handle<i::JSArray> arguments_jsarray =
424 i::Factory::NewJSArrayWithElements(arguments_array);
425 global_template->Set(String::New("arguments"),
426 Utils::ToLocal(arguments_jsarray));
427
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000428#ifdef ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000429 // Install the debugger object in the utility scope
430 i::Debug::Load();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000431 i::JSObject* debug = i::Debug::debug_context()->global();
432 utility_context_->Global()->Set(String::New("$debug"),
433 Utils::ToLocal(&debug));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000434#endif
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000435
436 // Run the d8 shell utility script in the utility context
437 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
438 i::Vector<const char> shell_source
439 = i::NativesCollection<i::D8>::GetScriptSource(source_index);
440 i::Vector<const char> shell_source_name
441 = i::NativesCollection<i::D8>::GetScriptName(source_index);
442 Handle<String> source = String::New(shell_source.start(),
443 shell_source.length());
444 Handle<String> name = String::New(shell_source_name.start(),
445 shell_source_name.length());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000446 Handle<Script> script = Script::Compile(source, name);
447 script->Run();
448
449 // Mark the d8 shell script as native to avoid it showing up as normal source
450 // in the debugger.
451 i::Handle<i::JSFunction> script_fun = Utils::OpenHandle(*script);
452 i::Handle<i::Script> script_object =
453 i::Handle<i::Script>(i::Script::cast(script_fun->shared()->script()));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000454 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000455
456 // Create the evaluation context
457 evaluation_context_ = Context::New(NULL, global_template);
458 evaluation_context_->SetSecurityToken(Undefined());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000459
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000460#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000461 // Set the security token of the debug context to allow access.
462 i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000463#endif
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000464}
465
466
467void Shell::OnExit() {
468 if (i::FLAG_dump_counters) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000469 ::printf("+----------------------------------------+-------------+\n");
470 ::printf("| Name | Value |\n");
471 ::printf("+----------------------------------------+-------------+\n");
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000472 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
473 Counter* counter = i.CurrentValue();
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000474 if (counter->is_histogram()) {
475 ::printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
476 ::printf("| t:%-36s | %11i |\n",
477 i.CurrentKey(),
478 counter->sample_total());
479 } else {
480 ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
481 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000482 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000483 ::printf("+----------------------------------------+-------------+\n");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000484 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000485 if (counters_file_ != NULL)
486 delete counters_file_;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000487}
488
489
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000490static char* ReadChars(const char* name, int* size_out) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000491 v8::Unlocker unlocker; // Release the V8 lock while reading files.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000492 FILE* file = i::OS::FOpen(name, "rb");
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000493 if (file == NULL) return NULL;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000494
495 fseek(file, 0, SEEK_END);
496 int size = ftell(file);
497 rewind(file);
498
499 char* chars = new char[size + 1];
500 chars[size] = '\0';
501 for (int i = 0; i < size;) {
502 int read = fread(&chars[i], 1, size - i, file);
503 i += read;
504 }
505 fclose(file);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000506 *size_out = size;
507 return chars;
508}
509
510
ager@chromium.org381abbb2009-02-25 13:23:22 +0000511static char* ReadToken(char* data, char token) {
512 char* next = i::OS::StrChr(data, token);
513 if (next != NULL) {
514 *next = '\0';
515 return (next + 1);
516 }
517
518 return NULL;
519}
520
521
522static char* ReadLine(char* data) {
523 return ReadToken(data, '\n');
524}
525
526
527static char* ReadWord(char* data) {
528 return ReadToken(data, ' ');
529}
530
531
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000532// Reads a file into a v8 string.
533Handle<String> Shell::ReadFile(const char* name) {
534 int size = 0;
535 char* chars = ReadChars(name, &size);
536 if (chars == NULL) return Handle<String>();
537 Handle<String> result = String::New(chars);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000538 delete[] chars;
539 return result;
540}
541
542
543void Shell::RunShell() {
544 LineEditor* editor = LineEditor::Get();
545 printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
546 editor->Open();
547 while (true) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000548 Locker locker;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000549 HandleScope handle_scope;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000550 Context::Scope context_scope(evaluation_context_);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000551 i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
552 if (input.is_empty())
553 break;
554 editor->AddHistory(*input);
555 Handle<String> name = String::New("(d8)");
556 ExecuteString(String::New(*input), name, true, true);
557 }
558 editor->Close();
559 printf("\n");
560}
561
562
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000563class ShellThread : public i::Thread {
564 public:
565 ShellThread(int no, i::Vector<const char> files)
566 : no_(no), files_(files) { }
567 virtual void Run();
568 private:
569 int no_;
570 i::Vector<const char> files_;
571};
572
573
574void ShellThread::Run() {
575 // Prepare the context for this thread.
576 Locker locker;
577 HandleScope scope;
578 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
579 global_template->Set(String::New("print"),
580 FunctionTemplate::New(Shell::Print));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000581 global_template->Set(String::New("read"),
582 FunctionTemplate::New(Shell::Read));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000583 global_template->Set(String::New("load"),
584 FunctionTemplate::New(Shell::Load));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000585 global_template->Set(String::New("yield"),
586 FunctionTemplate::New(Shell::Yield));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000587 global_template->Set(String::New("version"),
588 FunctionTemplate::New(Shell::Version));
589
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000590 char* ptr = const_cast<char*>(files_.start());
591 while ((ptr != NULL) && (*ptr != '\0')) {
592 // For each newline-separated line.
ager@chromium.org381abbb2009-02-25 13:23:22 +0000593 char* next_line = ReadLine(ptr);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000594
ager@chromium.org381abbb2009-02-25 13:23:22 +0000595 if (*ptr == '#') {
596 // Skip comment lines.
597 ptr = next_line;
598 continue;
599 }
600
601 Persistent<Context> thread_context = Context::New(NULL, global_template);
602 thread_context->SetSecurityToken(Undefined());
603 Context::Scope context_scope(thread_context);
604
605 while ((ptr != NULL) && (*ptr != '\0')) {
606 char* filename = ptr;
607 ptr = ReadWord(ptr);
608
609 // Skip empty strings.
610 if (strlen(filename) == 0) {
611 break;
612 }
613
614 Handle<String> str = Shell::ReadFile(filename);
615 if (str.IsEmpty()) {
616 printf("WARNING: %s not found\n", filename);
617 break;
618 }
619
620 Shell::ExecuteString(str, String::New(filename), false, false);
621 }
622
623 thread_context.Dispose();
624 ptr = next_line;
625 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000626}
627
628
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000629int Shell::Main(int argc, char* argv[]) {
630 i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000631 if (i::FLAG_help) {
632 return 1;
633 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000634 Initialize();
635 bool run_shell = (argc == 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000636
637 // Default use preemption if threads are created.
638 bool use_preemption = true;
639
640 // Default to use lowest possible thread preemption interval to test as many
641 // edgecases as possible.
642 int preemption_interval = 1;
643
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000644 i::List<i::Thread*> threads(1);
645
646 {
647 // Acquire the V8 lock once initialization has finished. Since the thread
648 // below may spawn new threads accessing V8 holding the V8 lock here is
649 // mandatory.
650 Locker locker;
651 Context::Scope context_scope(evaluation_context_);
652 for (int i = 1; i < argc; i++) {
653 char* str = argv[i];
654 if (strcmp(str, "--shell") == 0) {
655 run_shell = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000656 } else if (strcmp(str, "--preemption") == 0) {
657 use_preemption = true;
658 } else if (strcmp(str, "--no-preemption") == 0) {
659 use_preemption = false;
660 } else if (strcmp(str, "--preemption-interval") == 0) {
661 if (i + 1 < argc) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000662 char* end = NULL;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000663 preemption_interval = strtol(argv[++i], &end, 10); // NOLINT
664 if (preemption_interval <= 0 || *end != '\0' || errno == ERANGE) {
665 printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
666 return 1;
667 }
668 } else {
669 printf("Missing value for --preemption-interval\n");
670 return 1;
671 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000672 } else if (strcmp(str, "-f") == 0) {
673 // Ignore any -f flags for compatibility with other stand-alone
674 // JavaScript engines.
675 continue;
676 } else if (strncmp(str, "--", 2) == 0) {
677 printf("Warning: unknown flag %s.\nTry --help for options\n", str);
678 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
679 // Execute argument given to -e option directly.
680 v8::HandleScope handle_scope;
681 v8::Handle<v8::String> file_name = v8::String::New("unnamed");
682 v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000683 if (!ExecuteString(source, file_name, false, true)) {
684 OnExit();
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000685 return 1;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000686 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000687 i++;
688 } else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000689 int size = 0;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000690 const char* files = ReadChars(argv[++i], &size);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000691 if (files == NULL) return 1;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000692 ShellThread* thread =
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000693 new ShellThread(threads.length(),
694 i::Vector<const char>(files, size));
695 thread->Start();
696 threads.Add(thread);
697 } else {
698 // Use all other arguments as names of files to load and run.
699 HandleScope handle_scope;
700 Handle<String> file_name = v8::String::New(str);
701 Handle<String> source = ReadFile(str);
702 if (source.IsEmpty()) {
703 printf("Error reading '%s'\n", str);
704 return 1;
705 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000706 if (!ExecuteString(source, file_name, false, true)) {
707 OnExit();
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000708 return 1;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000709 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000710 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000711 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000712
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000713 // Start preemption if threads have been created and preemption is enabled.
714 if (threads.length() > 0 && use_preemption) {
715 Locker::StartPreemption(preemption_interval);
716 }
717
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000718#ifdef ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000719 // Run the remote debugger if requested.
720 if (i::FLAG_remote_debugger) {
721 RunRemoteDebugger(i::FLAG_debugger_port);
722 return 0;
723 }
724
725 // Start the debugger agent if requested.
726 if (i::FLAG_debugger_agent) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000727 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000728 }
729
730 // Start the in-process debugger if requested.
731 if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000732 v8::Debug::SetDebugEventListener(HandleDebugEvent);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000733 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000734#endif
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000735 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000736 if (run_shell)
737 RunShell();
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000738 for (int i = 0; i < threads.length(); i++) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000739 i::Thread* thread = threads[i];
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000740 thread->Join();
741 delete thread;
742 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000743 OnExit();
744 return 0;
745}
746
747
748} // namespace v8
749
750
751int main(int argc, char* argv[]) {
752 return v8::Shell::Main(argc, argv);
753}