blob: 7082280856e95c4984fd348a3c3d51280346cacf [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) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000149 Handle<Value> val = Write(args);
150 printf("\n");
151 return val;
152}
153
154
155Handle<Value> Shell::Write(const Arguments& args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000156 for (int i = 0; i < args.Length(); i++) {
157 HandleScope handle_scope;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000158 if (i != 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000159 printf(" ");
160 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000161 v8::String::Utf8Value str(args[i]);
162 const char* cstr = ToCString(str);
163 printf("%s", cstr);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000164 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000165 return Undefined();
166}
167
168
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000169Handle<Value> Shell::Read(const Arguments& args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000170 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
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000182Handle<Value> Shell::ReadLine(const Arguments& args) {
183 char line_buf[256];
184 if (fgets(line_buf, sizeof(line_buf), stdin) == NULL) {
185 return ThrowException(String::New("Error reading line"));
186 }
187 int len = strlen(line_buf);
188 if (line_buf[len - 1] == '\n') {
189 --len;
190 }
191 return String::New(line_buf, len);
192}
193
194
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000195Handle<Value> Shell::Load(const Arguments& args) {
196 for (int i = 0; i < args.Length(); i++) {
197 HandleScope handle_scope;
198 String::Utf8Value file(args[i]);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000199 if (*file == NULL) {
200 return ThrowException(String::New("Error loading file"));
201 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000202 Handle<String> source = ReadFile(*file);
203 if (source.IsEmpty()) {
204 return ThrowException(String::New("Error loading file"));
205 }
206 if (!ExecuteString(source, String::New(*file), false, false)) {
207 return ThrowException(String::New("Error executing file"));
208 }
209 }
210 return Undefined();
211}
212
213
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000214Handle<Value> Shell::Yield(const Arguments& args) {
215 v8::Unlocker unlocker;
216 return Undefined();
217}
218
219
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000220Handle<Value> Shell::Quit(const Arguments& args) {
221 int exit_code = args[0]->Int32Value();
222 OnExit();
223 exit(exit_code);
224 return Undefined();
225}
226
227
228Handle<Value> Shell::Version(const Arguments& args) {
229 return String::New(V8::GetVersion());
230}
231
232
233void Shell::ReportException(v8::TryCatch* try_catch) {
234 HandleScope handle_scope;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000235 v8::String::Utf8Value exception(try_catch->Exception());
236 const char* exception_string = ToCString(exception);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000237 Handle<Message> message = try_catch->Message();
238 if (message.IsEmpty()) {
239 // V8 didn't provide any extra information about this error; just
240 // print the exception.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000241 printf("%s\n", exception_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000242 } else {
243 // Print (filename):(line number): (message).
iposva@chromium.org245aa852009-02-10 00:49:54 +0000244 v8::String::Utf8Value filename(message->GetScriptResourceName());
245 const char* filename_string = ToCString(filename);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000246 int linenum = message->GetLineNumber();
iposva@chromium.org245aa852009-02-10 00:49:54 +0000247 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000248 // Print line of source code.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000249 v8::String::Utf8Value sourceline(message->GetSourceLine());
250 const char* sourceline_string = ToCString(sourceline);
251 printf("%s\n", sourceline_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000252 // Print wavy underline (GetUnderline is deprecated).
253 int start = message->GetStartColumn();
254 for (int i = 0; i < start; i++) {
255 printf(" ");
256 }
257 int end = message->GetEndColumn();
258 for (int i = start; i < end; i++) {
259 printf("^");
260 }
261 printf("\n");
262 }
263}
264
265
266Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
267 HandleScope handle_scope;
268 Context::Scope context_scope(utility_context_);
269 Handle<Object> global = utility_context_->Global();
270 Handle<Value> fun = global->Get(String::New("GetCompletions"));
271 static const int kArgc = 3;
272 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
273 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
274 return handle_scope.Close(Handle<Array>::Cast(val));
275}
276
277
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000278#ifdef ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000279Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000280 Context::Scope context_scope(utility_context_);
281 Handle<Object> global = utility_context_->Global();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000282 Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000283 static const int kArgc = 1;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000284 Handle<Value> argv[kArgc] = { message };
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000285 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000286 return Handle<Object>::Cast(val);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000287}
288
289
290Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
291 Context::Scope context_scope(utility_context_);
292 Handle<Object> global = utility_context_->Global();
293 Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
294 static const int kArgc = 1;
295 Handle<Value> argv[kArgc] = { command };
296 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
297 return val;
298}
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000299#endif
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000300
301
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000302int32_t* Counter::Bind(const char* name, bool is_histogram) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000303 int i;
304 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
305 name_[i] = static_cast<char>(name[i]);
306 name_[i] = '\0';
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000307 is_histogram_ = is_histogram;
308 return ptr();
309}
310
311
312void Counter::AddSample(int32_t sample) {
313 count_++;
314 sample_total_ += sample;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000315}
316
317
318CounterCollection::CounterCollection() {
319 magic_number_ = 0xDEADFACE;
320 max_counters_ = kMaxCounters;
321 max_name_size_ = Counter::kMaxNameSize;
322 counters_in_use_ = 0;
323}
324
325
326Counter* CounterCollection::GetNextCounter() {
327 if (counters_in_use_ == kMaxCounters) return NULL;
328 return &counters_[counters_in_use_++];
329}
330
331
332void Shell::MapCounters(const char* name) {
333 counters_file_ = i::OS::MemoryMappedFile::create(name,
334 sizeof(CounterCollection), &local_counters_);
335 void* memory = (counters_file_ == NULL) ?
336 NULL : counters_file_->memory();
337 if (memory == NULL) {
338 printf("Could not map counters file %s\n", name);
339 exit(1);
340 }
341 counters_ = static_cast<CounterCollection*>(memory);
342 V8::SetCounterFunction(LookupCounter);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000343 V8::SetCreateHistogramFunction(CreateHistogram);
344 V8::SetAddHistogramSampleFunction(AddHistogramSample);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000345}
346
347
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000348int CounterMap::Hash(const char* name) {
349 int h = 0;
350 int c;
351 while ((c = *name++) != 0) {
352 h += h << 5;
353 h += c;
354 }
355 return h;
356}
357
358
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000359Counter* Shell::GetCounter(const char* name, bool is_histogram) {
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000360 Counter* counter = counter_map_->Lookup(name);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000361
362 if (counter == NULL) {
363 counter = counters_->GetNextCounter();
364 if (counter != NULL) {
365 counter_map_->Set(name, counter);
366 counter->Bind(name, is_histogram);
367 }
368 } else {
369 ASSERT(counter->is_histogram() == is_histogram);
370 }
371 return counter;
372}
373
374
375int* Shell::LookupCounter(const char* name) {
376 Counter* counter = GetCounter(name, false);
377
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000378 if (counter != NULL) {
379 return counter->ptr();
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000380 } else {
381 return NULL;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000382 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000383}
384
385
386void* Shell::CreateHistogram(const char* name,
387 int min,
388 int max,
389 size_t buckets) {
390 return GetCounter(name, true);
391}
392
393
394void Shell::AddHistogramSample(void* histogram, int sample) {
395 Counter* counter = reinterpret_cast<Counter*>(histogram);
396 counter->AddSample(sample);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000397}
398
399
400void Shell::Initialize() {
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000401 Shell::counter_map_ = new CounterMap();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000402 // Set up counters
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000403 if (i::FLAG_map_counters != NULL)
404 MapCounters(i::FLAG_map_counters);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000405 if (i::FLAG_dump_counters) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000406 V8::SetCounterFunction(LookupCounter);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000407 V8::SetCreateHistogramFunction(CreateHistogram);
408 V8::SetAddHistogramSampleFunction(AddHistogramSample);
409 }
410
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000411 // Initialize the global objects
412 HandleScope scope;
413 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
414 global_template->Set(String::New("print"), FunctionTemplate::New(Print));
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000415 global_template->Set(String::New("write"), FunctionTemplate::New(Write));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000416 global_template->Set(String::New("read"), FunctionTemplate::New(Read));
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000417 global_template->Set(String::New("readline"),
418 FunctionTemplate::New(ReadLine));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000419 global_template->Set(String::New("load"), FunctionTemplate::New(Load));
420 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
421 global_template->Set(String::New("version"), FunctionTemplate::New(Version));
ager@chromium.org71daaf62009-04-01 07:22:49 +0000422
423 Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
424 AddOSMethods(os_templ);
425 global_template->Set(String::New("os"), os_templ);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000426
427 utility_context_ = Context::New(NULL, global_template);
428 utility_context_->SetSecurityToken(Undefined());
429 Context::Scope utility_scope(utility_context_);
430
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000431 i::JSArguments js_args = i::FLAG_js_arguments;
432 i::Handle<i::FixedArray> arguments_array =
433 i::Factory::NewFixedArray(js_args.argc());
434 for (int j = 0; j < js_args.argc(); j++) {
435 i::Handle<i::String> arg =
436 i::Factory::NewStringFromUtf8(i::CStrVector(js_args[j]));
437 arguments_array->set(j, *arg);
438 }
439 i::Handle<i::JSArray> arguments_jsarray =
440 i::Factory::NewJSArrayWithElements(arguments_array);
441 global_template->Set(String::New("arguments"),
442 Utils::ToLocal(arguments_jsarray));
443
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000444#ifdef ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000445 // Install the debugger object in the utility scope
446 i::Debug::Load();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000447 i::JSObject* debug = i::Debug::debug_context()->global();
448 utility_context_->Global()->Set(String::New("$debug"),
449 Utils::ToLocal(&debug));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000450#endif
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000451
452 // Run the d8 shell utility script in the utility context
453 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
454 i::Vector<const char> shell_source
455 = i::NativesCollection<i::D8>::GetScriptSource(source_index);
456 i::Vector<const char> shell_source_name
457 = i::NativesCollection<i::D8>::GetScriptName(source_index);
458 Handle<String> source = String::New(shell_source.start(),
459 shell_source.length());
460 Handle<String> name = String::New(shell_source_name.start(),
461 shell_source_name.length());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000462 Handle<Script> script = Script::Compile(source, name);
463 script->Run();
464
465 // Mark the d8 shell script as native to avoid it showing up as normal source
466 // in the debugger.
467 i::Handle<i::JSFunction> script_fun = Utils::OpenHandle(*script);
468 i::Handle<i::Script> script_object =
469 i::Handle<i::Script>(i::Script::cast(script_fun->shared()->script()));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000470 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000471
472 // Create the evaluation context
473 evaluation_context_ = Context::New(NULL, global_template);
474 evaluation_context_->SetSecurityToken(Undefined());
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000475
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000476#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000477 // Set the security token of the debug context to allow access.
478 i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000479
480 // Start the debugger agent if requested.
481 if (i::FLAG_debugger_agent) {
482 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port);
483 }
484
485 // Start the in-process debugger if requested.
486 if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
487 v8::Debug::SetDebugEventListener(HandleDebugEvent);
488 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000489#endif
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000490}
491
492
493void Shell::OnExit() {
494 if (i::FLAG_dump_counters) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000495 ::printf("+----------------------------------------+-------------+\n");
496 ::printf("| Name | Value |\n");
497 ::printf("+----------------------------------------+-------------+\n");
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000498 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
499 Counter* counter = i.CurrentValue();
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000500 if (counter->is_histogram()) {
501 ::printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
502 ::printf("| t:%-36s | %11i |\n",
503 i.CurrentKey(),
504 counter->sample_total());
505 } else {
506 ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
507 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000508 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000509 ::printf("+----------------------------------------+-------------+\n");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000510 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000511 if (counters_file_ != NULL)
512 delete counters_file_;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000513}
514
515
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000516static char* ReadChars(const char* name, int* size_out) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000517 v8::Unlocker unlocker; // Release the V8 lock while reading files.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000518 FILE* file = i::OS::FOpen(name, "rb");
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000519 if (file == NULL) return NULL;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000520
521 fseek(file, 0, SEEK_END);
522 int size = ftell(file);
523 rewind(file);
524
525 char* chars = new char[size + 1];
526 chars[size] = '\0';
527 for (int i = 0; i < size;) {
528 int read = fread(&chars[i], 1, size - i, file);
529 i += read;
530 }
531 fclose(file);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000532 *size_out = size;
533 return chars;
534}
535
536
ager@chromium.org381abbb2009-02-25 13:23:22 +0000537static char* ReadToken(char* data, char token) {
538 char* next = i::OS::StrChr(data, token);
539 if (next != NULL) {
540 *next = '\0';
541 return (next + 1);
542 }
543
544 return NULL;
545}
546
547
548static char* ReadLine(char* data) {
549 return ReadToken(data, '\n');
550}
551
552
553static char* ReadWord(char* data) {
554 return ReadToken(data, ' ');
555}
556
557
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000558// Reads a file into a v8 string.
559Handle<String> Shell::ReadFile(const char* name) {
560 int size = 0;
561 char* chars = ReadChars(name, &size);
562 if (chars == NULL) return Handle<String>();
563 Handle<String> result = String::New(chars);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000564 delete[] chars;
565 return result;
566}
567
568
569void Shell::RunShell() {
570 LineEditor* editor = LineEditor::Get();
571 printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
572 editor->Open();
573 while (true) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000574 Locker locker;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000575 HandleScope handle_scope;
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000576 Context::Scope context_scope(evaluation_context_);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000577 i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
578 if (input.is_empty())
579 break;
580 editor->AddHistory(*input);
581 Handle<String> name = String::New("(d8)");
582 ExecuteString(String::New(*input), name, true, true);
583 }
584 editor->Close();
585 printf("\n");
586}
587
588
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000589class ShellThread : public i::Thread {
590 public:
591 ShellThread(int no, i::Vector<const char> files)
592 : no_(no), files_(files) { }
593 virtual void Run();
594 private:
595 int no_;
596 i::Vector<const char> files_;
597};
598
599
600void ShellThread::Run() {
601 // Prepare the context for this thread.
602 Locker locker;
603 HandleScope scope;
604 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
605 global_template->Set(String::New("print"),
606 FunctionTemplate::New(Shell::Print));
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000607 global_template->Set(String::New("write"),
608 FunctionTemplate::New(Shell::Write));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000609 global_template->Set(String::New("read"),
610 FunctionTemplate::New(Shell::Read));
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000611 global_template->Set(String::New("readline"),
612 FunctionTemplate::New(Shell::ReadLine));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000613 global_template->Set(String::New("load"),
614 FunctionTemplate::New(Shell::Load));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000615 global_template->Set(String::New("yield"),
616 FunctionTemplate::New(Shell::Yield));
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000617 global_template->Set(String::New("version"),
618 FunctionTemplate::New(Shell::Version));
619
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000620 char* ptr = const_cast<char*>(files_.start());
621 while ((ptr != NULL) && (*ptr != '\0')) {
622 // For each newline-separated line.
ager@chromium.org381abbb2009-02-25 13:23:22 +0000623 char* next_line = ReadLine(ptr);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000624
ager@chromium.org381abbb2009-02-25 13:23:22 +0000625 if (*ptr == '#') {
626 // Skip comment lines.
627 ptr = next_line;
628 continue;
629 }
630
631 Persistent<Context> thread_context = Context::New(NULL, global_template);
632 thread_context->SetSecurityToken(Undefined());
633 Context::Scope context_scope(thread_context);
634
635 while ((ptr != NULL) && (*ptr != '\0')) {
636 char* filename = ptr;
637 ptr = ReadWord(ptr);
638
639 // Skip empty strings.
640 if (strlen(filename) == 0) {
641 break;
642 }
643
644 Handle<String> str = Shell::ReadFile(filename);
645 if (str.IsEmpty()) {
646 printf("WARNING: %s not found\n", filename);
647 break;
648 }
649
650 Shell::ExecuteString(str, String::New(filename), false, false);
651 }
652
653 thread_context.Dispose();
654 ptr = next_line;
655 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000656}
657
658
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000659int Shell::Main(int argc, char* argv[]) {
660 i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000661 if (i::FLAG_help) {
662 return 1;
663 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000664 Initialize();
665 bool run_shell = (argc == 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000666
667 // Default use preemption if threads are created.
668 bool use_preemption = true;
669
670 // Default to use lowest possible thread preemption interval to test as many
671 // edgecases as possible.
672 int preemption_interval = 1;
673
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000674 i::List<i::Thread*> threads(1);
675
676 {
677 // Acquire the V8 lock once initialization has finished. Since the thread
678 // below may spawn new threads accessing V8 holding the V8 lock here is
679 // mandatory.
680 Locker locker;
681 Context::Scope context_scope(evaluation_context_);
682 for (int i = 1; i < argc; i++) {
683 char* str = argv[i];
684 if (strcmp(str, "--shell") == 0) {
685 run_shell = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000686 } else if (strcmp(str, "--preemption") == 0) {
687 use_preemption = true;
688 } else if (strcmp(str, "--no-preemption") == 0) {
689 use_preemption = false;
690 } else if (strcmp(str, "--preemption-interval") == 0) {
691 if (i + 1 < argc) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000692 char* end = NULL;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000693 preemption_interval = strtol(argv[++i], &end, 10); // NOLINT
694 if (preemption_interval <= 0 || *end != '\0' || errno == ERANGE) {
695 printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
696 return 1;
697 }
698 } else {
699 printf("Missing value for --preemption-interval\n");
700 return 1;
701 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000702 } else if (strcmp(str, "-f") == 0) {
703 // Ignore any -f flags for compatibility with other stand-alone
704 // JavaScript engines.
705 continue;
706 } else if (strncmp(str, "--", 2) == 0) {
707 printf("Warning: unknown flag %s.\nTry --help for options\n", str);
708 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
709 // Execute argument given to -e option directly.
710 v8::HandleScope handle_scope;
711 v8::Handle<v8::String> file_name = v8::String::New("unnamed");
712 v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000713 if (!ExecuteString(source, file_name, false, true)) {
714 OnExit();
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000715 return 1;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000716 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000717 i++;
718 } else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000719 int size = 0;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000720 const char* files = ReadChars(argv[++i], &size);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000721 if (files == NULL) return 1;
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000722 ShellThread* thread =
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000723 new ShellThread(threads.length(),
724 i::Vector<const char>(files, size));
725 thread->Start();
726 threads.Add(thread);
727 } else {
728 // Use all other arguments as names of files to load and run.
729 HandleScope handle_scope;
730 Handle<String> file_name = v8::String::New(str);
731 Handle<String> source = ReadFile(str);
732 if (source.IsEmpty()) {
733 printf("Error reading '%s'\n", str);
734 return 1;
735 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000736 if (!ExecuteString(source, file_name, false, true)) {
737 OnExit();
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000738 return 1;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000739 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000740 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000741 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000742
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000743 // Start preemption if threads have been created and preemption is enabled.
744 if (threads.length() > 0 && use_preemption) {
745 Locker::StartPreemption(preemption_interval);
746 }
747
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000748#ifdef ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000749 // Run the remote debugger if requested.
750 if (i::FLAG_remote_debugger) {
751 RunRemoteDebugger(i::FLAG_debugger_port);
752 return 0;
753 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000754#endif
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000755 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000756 if (run_shell)
757 RunShell();
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000758 for (int i = 0; i < threads.length(); i++) {
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000759 i::Thread* thread = threads[i];
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000760 thread->Join();
761 delete thread;
762 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000763 OnExit();
764 return 0;
765}
766
767
768} // namespace v8
769
770
771int main(int argc, char* argv[]) {
772 return v8::Shell::Main(argc, argv);
773}