blob: 55f0d4c2ab57cf74b0027a7c12c81f6df8573f20 [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 Murdoch69a99ed2011-11-30 16:03:39 +0000149#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000150 bool FLAG_debugger = i::FLAG_debugger;
151#else
152 bool FLAG_debugger = false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000153#endif // V8_SHARED
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 Murdoch589d6972011-11-30 16:04:58 +0000181 fwrite(*str, sizeof(**str), str.length(), stdout);
182 printf("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000183 }
184 return true;
185 }
186 }
187}
188
189
190Handle<Value> Shell::Print(const Arguments& args) {
191 Handle<Value> val = Write(args);
192 printf("\n");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000193 fflush(stdout);
Steve Blocka7e24c12009-10-30 11:49:00 +0000194 return val;
195}
196
197
198Handle<Value> Shell::Write(const Arguments& args) {
199 for (int i = 0; i < args.Length(); i++) {
200 HandleScope handle_scope;
201 if (i != 0) {
202 printf(" ");
203 }
204 v8::String::Utf8Value str(args[i]);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000205 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
Steve Blockd0582a62009-12-15 09:54:21 +0000206 if (n != str.length()) {
207 printf("Error in fwrite\n");
Ben Murdoch589d6972011-11-30 16:04:58 +0000208 Exit(1);
Steve Blockd0582a62009-12-15 09:54:21 +0000209 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000210 }
211 return Undefined();
212}
213
214
Ben Murdoch589d6972011-11-30 16:04:58 +0000215Handle<Value> Shell::EnableProfiler(const Arguments& args) {
216 V8::ResumeProfiler();
217 return Undefined();
218}
219
220
221Handle<Value> Shell::DisableProfiler(const Arguments& args) {
222 V8::PauseProfiler();
223 return Undefined();
224}
225
226
Steve Blocka7e24c12009-10-30 11:49:00 +0000227Handle<Value> Shell::Read(const Arguments& args) {
228 String::Utf8Value file(args[0]);
229 if (*file == NULL) {
230 return ThrowException(String::New("Error loading file"));
231 }
232 Handle<String> source = ReadFile(*file);
233 if (source.IsEmpty()) {
234 return ThrowException(String::New("Error loading file"));
235 }
236 return source;
237}
238
239
240Handle<Value> Shell::ReadLine(const Arguments& args) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000241 static const int kBufferSize = 256;
242 char buffer[kBufferSize];
243 Handle<String> accumulator = String::New("");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000244 int length;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000245 while (true) {
246 // Continue reading if the line ends with an escape '\\' or the line has
247 // not been fully read into the buffer yet (does not end with '\n').
248 // If fgets gets an error, just give up.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000249 if (fgets(buffer, kBufferSize, stdin) == NULL) return Null();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000250 length = static_cast<int>(strlen(buffer));
251 if (length == 0) {
252 return accumulator;
253 } else if (buffer[length-1] != '\n') {
254 accumulator = String::Concat(accumulator, String::New(buffer, length));
255 } else if (length > 1 && buffer[length-2] == '\\') {
256 buffer[length-2] = '\n';
257 accumulator = String::Concat(accumulator, String::New(buffer, length-1));
258 } else {
259 return String::Concat(accumulator, String::New(buffer, length-1));
260 }
261 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000262}
263
264
265Handle<Value> Shell::Load(const Arguments& args) {
266 for (int i = 0; i < args.Length(); i++) {
267 HandleScope handle_scope;
268 String::Utf8Value file(args[i]);
269 if (*file == NULL) {
270 return ThrowException(String::New("Error loading file"));
271 }
272 Handle<String> source = ReadFile(*file);
273 if (source.IsEmpty()) {
274 return ThrowException(String::New("Error loading file"));
275 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000276 if (!ExecuteString(source, String::New(*file), false, true)) {
Steve Blockd0582a62009-12-15 09:54:21 +0000277 return ThrowException(String::New("Error executing file"));
Steve Blocka7e24c12009-10-30 11:49:00 +0000278 }
279 }
280 return Undefined();
281}
282
283
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000284Handle<Value> Shell::CreateExternalArray(const Arguments& args,
285 ExternalArrayType type,
286 size_t element_size) {
287 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 ||
288 element_size == 8);
289 if (args.Length() != 1) {
290 return ThrowException(
291 String::New("Array constructor needs one parameter."));
292 }
293 static const int kMaxLength = 0x3fffffff;
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000294#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000295 ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000296#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000297 size_t length = 0;
298 if (args[0]->IsUint32()) {
299 length = args[0]->Uint32Value();
Ben Murdoch589d6972011-11-30 16:04:58 +0000300 } else {
301 Local<Number> number = args[0]->ToNumber();
302 if (number.IsEmpty() || !number->IsNumber()) {
303 return ThrowException(String::New("Array length must be a number."));
304 }
305 int32_t raw_length = number->ToInt32()->Int32Value();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000306 if (raw_length < 0) {
307 return ThrowException(String::New("Array length must not be negative."));
308 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000309 if (raw_length > static_cast<int32_t>(kMaxLength)) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000310 return ThrowException(
311 String::New("Array length exceeds maximum length."));
312 }
313 length = static_cast<size_t>(raw_length);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000314 }
315 if (length > static_cast<size_t>(kMaxLength)) {
316 return ThrowException(String::New("Array length exceeds maximum length."));
317 }
318 void* data = calloc(length, element_size);
319 if (data == NULL) {
320 return ThrowException(String::New("Memory allocation failed."));
321 }
322 Handle<Object> array = Object::New();
323 Persistent<Object> persistent_array = Persistent<Object>::New(array);
324 persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
325 persistent_array.MarkIndependent();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000326 array->SetIndexedPropertiesToExternalArrayData(data, type,
327 static_cast<int>(length));
328 array->Set(String::New("length"),
329 Int32::New(static_cast<int32_t>(length)), ReadOnly);
330 array->Set(String::New("BYTES_PER_ELEMENT"),
331 Int32::New(static_cast<int32_t>(element_size)));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000332 return array;
333}
334
335
336void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
337 free(data);
338 object.Dispose();
339}
340
341
342Handle<Value> Shell::Int8Array(const Arguments& args) {
343 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
344}
345
346
347Handle<Value> Shell::Uint8Array(const Arguments& args) {
348 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t));
349}
350
351
352Handle<Value> Shell::Int16Array(const Arguments& args) {
353 return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t));
354}
355
356
357Handle<Value> Shell::Uint16Array(const Arguments& args) {
358 return CreateExternalArray(args, kExternalUnsignedShortArray,
359 sizeof(uint16_t));
360}
361
362
363Handle<Value> Shell::Int32Array(const Arguments& args) {
364 return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t));
365}
366
367
368Handle<Value> Shell::Uint32Array(const Arguments& args) {
369 return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t));
370}
371
372
373Handle<Value> Shell::Float32Array(const Arguments& args) {
374 return CreateExternalArray(args, kExternalFloatArray,
375 sizeof(float)); // NOLINT
376}
377
378
379Handle<Value> Shell::Float64Array(const Arguments& args) {
380 return CreateExternalArray(args, kExternalDoubleArray,
381 sizeof(double)); // NOLINT
382}
383
384
385Handle<Value> Shell::PixelArray(const Arguments& args) {
386 return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t));
387}
388
389
Steve Blocka7e24c12009-10-30 11:49:00 +0000390Handle<Value> Shell::Yield(const Arguments& args) {
391 v8::Unlocker unlocker;
392 return Undefined();
393}
394
395
396Handle<Value> Shell::Quit(const Arguments& args) {
397 int exit_code = args[0]->Int32Value();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000398#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000399 OnExit();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000400#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000401 exit(exit_code);
402 return Undefined();
403}
404
405
406Handle<Value> Shell::Version(const Arguments& args) {
407 return String::New(V8::GetVersion());
408}
409
410
411void Shell::ReportException(v8::TryCatch* try_catch) {
412 HandleScope handle_scope;
413 v8::String::Utf8Value exception(try_catch->Exception());
414 const char* exception_string = ToCString(exception);
415 Handle<Message> message = try_catch->Message();
416 if (message.IsEmpty()) {
417 // V8 didn't provide any extra information about this error; just
418 // print the exception.
419 printf("%s\n", exception_string);
420 } else {
421 // Print (filename):(line number): (message).
422 v8::String::Utf8Value filename(message->GetScriptResourceName());
423 const char* filename_string = ToCString(filename);
424 int linenum = message->GetLineNumber();
425 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
426 // Print line of source code.
427 v8::String::Utf8Value sourceline(message->GetSourceLine());
428 const char* sourceline_string = ToCString(sourceline);
429 printf("%s\n", sourceline_string);
430 // Print wavy underline (GetUnderline is deprecated).
431 int start = message->GetStartColumn();
432 for (int i = 0; i < start; i++) {
433 printf(" ");
434 }
435 int end = message->GetEndColumn();
436 for (int i = start; i < end; i++) {
437 printf("^");
438 }
439 printf("\n");
Ben Murdoch257744e2011-11-30 15:57:28 +0000440 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
441 if (stack_trace.length() > 0) {
442 const char* stack_trace_string = ToCString(stack_trace);
443 printf("%s\n", stack_trace_string);
444 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000445 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000446 printf("\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000447}
448
449
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000450#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000451Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
452 HandleScope handle_scope;
453 Context::Scope context_scope(utility_context_);
454 Handle<Object> global = utility_context_->Global();
455 Handle<Value> fun = global->Get(String::New("GetCompletions"));
456 static const int kArgc = 3;
457 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
458 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
459 return handle_scope.Close(Handle<Array>::Cast(val));
460}
461
462
463#ifdef ENABLE_DEBUGGER_SUPPORT
464Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
465 Context::Scope context_scope(utility_context_);
466 Handle<Object> global = utility_context_->Global();
467 Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
468 static const int kArgc = 1;
469 Handle<Value> argv[kArgc] = { message };
470 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
471 return Handle<Object>::Cast(val);
472}
473
474
475Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
476 Context::Scope context_scope(utility_context_);
477 Handle<Object> global = utility_context_->Global();
478 Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
479 static const int kArgc = 1;
480 Handle<Value> argv[kArgc] = { command };
481 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
482 return val;
483}
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000484#endif // ENABLE_DEBUGGER_SUPPORT
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000485#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000486
487
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000488#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000489int32_t* Counter::Bind(const char* name, bool is_histogram) {
490 int i;
491 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
492 name_[i] = static_cast<char>(name[i]);
493 name_[i] = '\0';
494 is_histogram_ = is_histogram;
495 return ptr();
496}
497
498
499void Counter::AddSample(int32_t sample) {
500 count_++;
501 sample_total_ += sample;
502}
503
504
505CounterCollection::CounterCollection() {
506 magic_number_ = 0xDEADFACE;
507 max_counters_ = kMaxCounters;
508 max_name_size_ = Counter::kMaxNameSize;
509 counters_in_use_ = 0;
510}
511
512
513Counter* CounterCollection::GetNextCounter() {
514 if (counters_in_use_ == kMaxCounters) return NULL;
515 return &counters_[counters_in_use_++];
516}
517
518
519void Shell::MapCounters(const char* name) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000520 counters_file_ = i::OS::MemoryMappedFile::create(
521 name, sizeof(CounterCollection), &local_counters_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000522 void* memory = (counters_file_ == NULL) ?
523 NULL : counters_file_->memory();
524 if (memory == NULL) {
525 printf("Could not map counters file %s\n", name);
Ben Murdoch589d6972011-11-30 16:04:58 +0000526 Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000527 }
528 counters_ = static_cast<CounterCollection*>(memory);
529 V8::SetCounterFunction(LookupCounter);
530 V8::SetCreateHistogramFunction(CreateHistogram);
531 V8::SetAddHistogramSampleFunction(AddHistogramSample);
532}
533
534
535int CounterMap::Hash(const char* name) {
536 int h = 0;
537 int c;
538 while ((c = *name++) != 0) {
539 h += h << 5;
540 h += c;
541 }
542 return h;
543}
544
545
546Counter* Shell::GetCounter(const char* name, bool is_histogram) {
547 Counter* counter = counter_map_->Lookup(name);
548
549 if (counter == NULL) {
550 counter = counters_->GetNextCounter();
551 if (counter != NULL) {
552 counter_map_->Set(name, counter);
553 counter->Bind(name, is_histogram);
554 }
555 } else {
556 ASSERT(counter->is_histogram() == is_histogram);
557 }
558 return counter;
559}
560
561
562int* Shell::LookupCounter(const char* name) {
563 Counter* counter = GetCounter(name, false);
564
565 if (counter != NULL) {
566 return counter->ptr();
567 } else {
568 return NULL;
569 }
570}
571
572
573void* Shell::CreateHistogram(const char* name,
574 int min,
575 int max,
576 size_t buckets) {
577 return GetCounter(name, true);
578}
579
580
581void Shell::AddHistogramSample(void* histogram, int sample) {
582 Counter* counter = reinterpret_cast<Counter*>(histogram);
583 counter->AddSample(sample);
584}
585
586
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000587void Shell::InstallUtilityScript() {
588 Locker lock;
Steve Blocka7e24c12009-10-30 11:49:00 +0000589 HandleScope scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000590 // If we use the utility context, we have to set the security tokens so that
591 // utility, evaluation and debug context can all access each other.
Steve Blocka7e24c12009-10-30 11:49:00 +0000592 utility_context_->SetSecurityToken(Undefined());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000593 evaluation_context_->SetSecurityToken(Undefined());
Steve Blocka7e24c12009-10-30 11:49:00 +0000594 Context::Scope utility_scope(utility_context_);
595
Steve Blocka7e24c12009-10-30 11:49:00 +0000596#ifdef ENABLE_DEBUGGER_SUPPORT
597 // Install the debugger object in the utility scope
Steve Block44f0eee2011-05-26 01:26:41 +0100598 i::Debug* debug = i::Isolate::Current()->debug();
599 debug->Load();
600 i::Handle<i::JSObject> js_debug
601 = i::Handle<i::JSObject>(debug->debug_context()->global());
Steve Blocka7e24c12009-10-30 11:49:00 +0000602 utility_context_->Global()->Set(String::New("$debug"),
Steve Block44f0eee2011-05-26 01:26:41 +0100603 Utils::ToLocal(js_debug));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000604 debug->debug_context()->set_security_token(HEAP->undefined_value());
605#endif // ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +0000606
607 // Run the d8 shell utility script in the utility context
608 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000609 i::Vector<const char> shell_source =
610 i::NativesCollection<i::D8>::GetRawScriptSource(source_index);
611 i::Vector<const char> shell_source_name =
612 i::NativesCollection<i::D8>::GetScriptName(source_index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 Handle<String> source = String::New(shell_source.start(),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000614 shell_source.length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000615 Handle<String> name = String::New(shell_source_name.start(),
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000616 shell_source_name.length());
Steve Blocka7e24c12009-10-30 11:49:00 +0000617 Handle<Script> script = Script::Compile(source, name);
618 script->Run();
Steve Blocka7e24c12009-10-30 11:49:00 +0000619 // Mark the d8 shell script as native to avoid it showing up as normal source
620 // in the debugger.
Steve Block6ded16b2010-05-10 14:33:55 +0100621 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
622 i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
623 ? i::Handle<i::Script>(i::Script::cast(
624 i::JSFunction::cast(*compiled_script)->shared()->script()))
625 : i::Handle<i::Script>(i::Script::cast(
626 i::SharedFunctionInfo::cast(*compiled_script)->script()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000627 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
628
Steve Blocka7e24c12009-10-30 11:49:00 +0000629#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +0000630 // Start the in-process debugger if requested.
631 if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
632 v8::Debug::SetDebugEventListener(HandleDebugEvent);
633 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000634#endif // ENABLE_DEBUGGER_SUPPORT
635}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000636#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000637
638
639#ifdef COMPRESS_STARTUP_DATA_BZ2
640class BZip2Decompressor : public v8::StartupDataDecompressor {
641 public:
642 virtual ~BZip2Decompressor() { }
643
644 protected:
645 virtual int DecompressData(char* raw_data,
646 int* raw_data_size,
647 const char* compressed_data,
648 int compressed_data_size) {
649 ASSERT_EQ(v8::StartupData::kBZip2,
650 v8::V8::GetCompressedStartupDataAlgorithm());
651 unsigned int decompressed_size = *raw_data_size;
652 int result =
653 BZ2_bzBuffToBuffDecompress(raw_data,
654 &decompressed_size,
655 const_cast<char*>(compressed_data),
656 compressed_data_size,
657 0, 1);
658 if (result == BZ_OK) {
659 *raw_data_size = decompressed_size;
660 }
661 return result;
662 }
663};
Steve Blocka7e24c12009-10-30 11:49:00 +0000664#endif
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000665
666Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
667 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
668 global_template->Set(String::New("print"), FunctionTemplate::New(Print));
669 global_template->Set(String::New("write"), FunctionTemplate::New(Write));
670 global_template->Set(String::New("read"), FunctionTemplate::New(Read));
671 global_template->Set(String::New("readline"),
672 FunctionTemplate::New(ReadLine));
673 global_template->Set(String::New("load"), FunctionTemplate::New(Load));
674 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
675 global_template->Set(String::New("version"), FunctionTemplate::New(Version));
Ben Murdoch589d6972011-11-30 16:04:58 +0000676 global_template->Set(String::New("enableProfiler"),
677 FunctionTemplate::New(EnableProfiler));
678 global_template->Set(String::New("disableProfiler"),
679 FunctionTemplate::New(DisableProfiler));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000680
681 // Bind the handlers for external arrays.
682 global_template->Set(String::New("Int8Array"),
683 FunctionTemplate::New(Int8Array));
684 global_template->Set(String::New("Uint8Array"),
685 FunctionTemplate::New(Uint8Array));
686 global_template->Set(String::New("Int16Array"),
687 FunctionTemplate::New(Int16Array));
688 global_template->Set(String::New("Uint16Array"),
689 FunctionTemplate::New(Uint16Array));
690 global_template->Set(String::New("Int32Array"),
691 FunctionTemplate::New(Int32Array));
692 global_template->Set(String::New("Uint32Array"),
693 FunctionTemplate::New(Uint32Array));
694 global_template->Set(String::New("Float32Array"),
695 FunctionTemplate::New(Float32Array));
696 global_template->Set(String::New("Float64Array"),
697 FunctionTemplate::New(Float64Array));
698 global_template->Set(String::New("PixelArray"),
699 FunctionTemplate::New(PixelArray));
700
701#ifdef LIVE_OBJECT_LIST
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000702 global_template->Set(String::New("lol_is_enabled"), True());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000703#else
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000704 global_template->Set(String::New("lol_is_enabled"), False());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000705#endif
706
Ben Murdoch589d6972011-11-30 16:04:58 +0000707#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000708 Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
709 AddOSMethods(os_templ);
710 global_template->Set(String::New("os"), os_templ);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000711#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000712
713 return global_template;
Steve Blocka7e24c12009-10-30 11:49:00 +0000714}
715
716
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000717void Shell::Initialize() {
718#ifdef COMPRESS_STARTUP_DATA_BZ2
719 BZip2Decompressor startup_data_decompressor;
720 int bz2_result = startup_data_decompressor.Decompress();
721 if (bz2_result != BZ_OK) {
722 fprintf(stderr, "bzip error code: %d\n", bz2_result);
Ben Murdoch589d6972011-11-30 16:04:58 +0000723 Exit(1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000724 }
725#endif
726
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000727#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000728 Shell::counter_map_ = new CounterMap();
729 // Set up counters
730 if (i::StrLength(i::FLAG_map_counters) != 0)
731 MapCounters(i::FLAG_map_counters);
732 if (i::FLAG_dump_counters) {
733 V8::SetCounterFunction(LookupCounter);
734 V8::SetCreateHistogramFunction(CreateHistogram);
735 V8::SetAddHistogramSampleFunction(AddHistogramSample);
736 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000737#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000738 if (options.test_shell) return;
739
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000740#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000741 Locker lock;
742 HandleScope scope;
743 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
744 utility_context_ = Context::New(NULL, global_template);
745
746#ifdef ENABLE_DEBUGGER_SUPPORT
747 // Start the debugger agent if requested.
748 if (i::FLAG_debugger_agent) {
749 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
750 }
751#endif // ENABLE_DEBUGGER_SUPPORT
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000752#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000753}
754
755
756Persistent<Context> Shell::CreateEvaluationContext() {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000757#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000758 // This needs to be a critical section since this is not thread-safe
759 i::ScopedLock lock(context_mutex_);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000760#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000761 // Initialize the global objects
762 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
763 Persistent<Context> context = Context::New(NULL, global_template);
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000764 ASSERT(!context.IsEmpty());
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000765 Context::Scope scope(context);
766
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000767#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000768 i::JSArguments js_args = i::FLAG_js_arguments;
769 i::Handle<i::FixedArray> arguments_array =
770 FACTORY->NewFixedArray(js_args.argc());
771 for (int j = 0; j < js_args.argc(); j++) {
772 i::Handle<i::String> arg =
773 FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
774 arguments_array->set(j, *arg);
775 }
776 i::Handle<i::JSArray> arguments_jsarray =
777 FACTORY->NewJSArrayWithElements(arguments_array);
778 context->Global()->Set(String::New("arguments"),
779 Utils::ToLocal(arguments_jsarray));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000780#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000781 return context;
782}
783
784
Ben Murdoch589d6972011-11-30 16:04:58 +0000785void Shell::Exit(int exit_code) {
786 // Use _exit instead of exit to avoid races between isolate
787 // threads and static destructors.
788 fflush(stdout);
789 fflush(stderr);
790 _exit(exit_code);
791}
792
793
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000794#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000795void Shell::OnExit() {
Ben Murdoch589d6972011-11-30 16:04:58 +0000796 if (console != NULL) console->Close();
Steve Blocka7e24c12009-10-30 11:49:00 +0000797 if (i::FLAG_dump_counters) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000798 printf("+----------------------------------------+-------------+\n");
799 printf("| Name | Value |\n");
800 printf("+----------------------------------------+-------------+\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000801 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
802 Counter* counter = i.CurrentValue();
803 if (counter->is_histogram()) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000804 printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
805 printf("| t:%-36s | %11i |\n", i.CurrentKey(), counter->sample_total());
Steve Blocka7e24c12009-10-30 11:49:00 +0000806 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000807 printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 }
809 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000810 printf("+----------------------------------------+-------------+\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000811 }
812 if (counters_file_ != NULL)
813 delete counters_file_;
814}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000815#endif // V8_SHARED
816
817
818static FILE* FOpen(const char* path, const char* mode) {
819#if (defined(_WIN32) || defined(_WIN64))
820 FILE* result;
821 if (fopen_s(&result, path, mode) == 0) {
822 return result;
823 } else {
824 return NULL;
825 }
826#else
827 FILE* file = fopen(path, mode);
828 if (file == NULL) return NULL;
829 struct stat file_stat;
830 if (fstat(fileno(file), &file_stat) != 0) return NULL;
831 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
832 if (is_regular_file) return file;
833 fclose(file);
834 return NULL;
835#endif
836}
Steve Blocka7e24c12009-10-30 11:49:00 +0000837
838
839static char* ReadChars(const char* name, int* size_out) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000840 // Release the V8 lock while reading files.
841 v8::Unlocker unlocker(Isolate::GetCurrent());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000842 FILE* file = FOpen(name, "rb");
Steve Blocka7e24c12009-10-30 11:49:00 +0000843 if (file == NULL) return NULL;
844
845 fseek(file, 0, SEEK_END);
846 int size = ftell(file);
847 rewind(file);
848
849 char* chars = new char[size + 1];
850 chars[size] = '\0';
851 for (int i = 0; i < size;) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000852 int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
Steve Blocka7e24c12009-10-30 11:49:00 +0000853 i += read;
854 }
855 fclose(file);
856 *size_out = size;
857 return chars;
858}
859
860
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000861#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000862static char* ReadToken(char* data, char token) {
863 char* next = i::OS::StrChr(data, token);
864 if (next != NULL) {
865 *next = '\0';
866 return (next + 1);
867 }
868
869 return NULL;
870}
871
872
873static char* ReadLine(char* data) {
874 return ReadToken(data, '\n');
875}
876
877
878static char* ReadWord(char* data) {
879 return ReadToken(data, ' ');
880}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000881#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000882
883
884// Reads a file into a v8 string.
885Handle<String> Shell::ReadFile(const char* name) {
886 int size = 0;
887 char* chars = ReadChars(name, &size);
888 if (chars == NULL) return Handle<String>();
889 Handle<String> result = String::New(chars);
890 delete[] chars;
891 return result;
892}
893
894
895void Shell::RunShell() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000896 Locker locker;
897 Context::Scope context_scope(evaluation_context_);
Ben Murdoch589d6972011-11-30 16:04:58 +0000898 HandleScope outer_scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000899 Handle<String> name = String::New("(d8)");
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000900#ifndef V8_SHARED
Ben Murdoch589d6972011-11-30 16:04:58 +0000901 console = LineEditor::Get();
902 printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100903 if (i::FLAG_debugger) {
904 printf("JavaScript debugger enabled\n");
905 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000906 console->Open();
Steve Blocka7e24c12009-10-30 11:49:00 +0000907 while (true) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000908 i::SmartArrayPointer<char> input = console->Prompt(Shell::kPrompt);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000909 if (input.is_empty()) break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000910 console->AddHistory(*input);
911 HandleScope inner_scope;
Steve Blocka7e24c12009-10-30 11:49:00 +0000912 ExecuteString(String::New(*input), name, true, true);
913 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000914#else
915 printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion());
916 static const int kBufferSize = 256;
917 while (true) {
918 char buffer[kBufferSize];
919 printf("%s", Shell::kPrompt);
920 if (fgets(buffer, kBufferSize, stdin) == NULL) break;
Ben Murdoch589d6972011-11-30 16:04:58 +0000921 HandleScope inner_scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000922 ExecuteString(String::New(buffer), name, true, true);
923 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000924#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000925 printf("\n");
926}
927
928
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000929#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000930class ShellThread : public i::Thread {
931 public:
Ben Murdoch589d6972011-11-30 16:04:58 +0000932 // Takes ownership of the underlying char array of |files|.
933 ShellThread(int no, char* files)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000934 : Thread("d8:ShellThread"),
935 no_(no), files_(files) { }
Ben Murdoch589d6972011-11-30 16:04:58 +0000936
937 ~ShellThread() {
938 delete[] files_;
939 }
940
Steve Blocka7e24c12009-10-30 11:49:00 +0000941 virtual void Run();
942 private:
943 int no_;
Ben Murdoch589d6972011-11-30 16:04:58 +0000944 char* files_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000945};
946
947
948void ShellThread::Run() {
Ben Murdoch589d6972011-11-30 16:04:58 +0000949 char* ptr = files_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000950 while ((ptr != NULL) && (*ptr != '\0')) {
951 // For each newline-separated line.
952 char* next_line = ReadLine(ptr);
953
954 if (*ptr == '#') {
955 // Skip comment lines.
956 ptr = next_line;
957 continue;
958 }
959
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000960 // Prepare the context for this thread.
961 Locker locker;
Ben Murdoch589d6972011-11-30 16:04:58 +0000962 HandleScope outer_scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000963 Persistent<Context> thread_context = Shell::CreateEvaluationContext();
Steve Blocka7e24c12009-10-30 11:49:00 +0000964 Context::Scope context_scope(thread_context);
965
966 while ((ptr != NULL) && (*ptr != '\0')) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000967 HandleScope inner_scope;
Steve Blocka7e24c12009-10-30 11:49:00 +0000968 char* filename = ptr;
969 ptr = ReadWord(ptr);
970
971 // Skip empty strings.
972 if (strlen(filename) == 0) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000973 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000974 }
975
976 Handle<String> str = Shell::ReadFile(filename);
977 if (str.IsEmpty()) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000978 printf("File '%s' not found\n", filename);
979 Shell::Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000980 }
981
982 Shell::ExecuteString(str, String::New(filename), false, false);
983 }
984
985 thread_context.Dispose();
986 ptr = next_line;
987 }
988}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000989#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000990
991
Ben Murdoch589d6972011-11-30 16:04:58 +0000992SourceGroup::~SourceGroup() {
993#ifndef V8_SHARED
994 delete next_semaphore_;
995 next_semaphore_ = NULL;
996 delete done_semaphore_;
997 done_semaphore_ = NULL;
998 delete thread_;
999 thread_ = NULL;
1000#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001001}
Steve Blocka7e24c12009-10-30 11:49:00 +00001002
Steve Blocka7e24c12009-10-30 11:49:00 +00001003
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001004void SourceGroup::Execute() {
1005 for (int i = begin_offset_; i < end_offset_; ++i) {
1006 const char* arg = argv_[i];
1007 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1008 // Execute argument given to -e option directly.
1009 HandleScope handle_scope;
1010 Handle<String> file_name = String::New("unnamed");
1011 Handle<String> source = String::New(argv_[i + 1]);
1012 if (!Shell::ExecuteString(source, file_name, false, true)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001013 Shell::Exit(1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001014 }
1015 ++i;
1016 } else if (arg[0] == '-') {
1017 // Ignore other options. They have been parsed already.
1018 } else {
1019 // Use all other arguments as names of files to load and run.
1020 HandleScope handle_scope;
1021 Handle<String> file_name = String::New(arg);
1022 Handle<String> source = ReadFile(arg);
1023 if (source.IsEmpty()) {
1024 printf("Error reading '%s'\n", arg);
Ben Murdoch589d6972011-11-30 16:04:58 +00001025 Shell::Exit(1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001026 }
1027 if (!Shell::ExecuteString(source, file_name, false, true)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001028 Shell::Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001029 }
1030 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001031 }
1032}
Steve Blocka7e24c12009-10-30 11:49:00 +00001033
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001034
1035Handle<String> SourceGroup::ReadFile(const char* name) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001036 int size;
1037 const char* chars = ReadChars(name, &size);
1038 if (chars == NULL) return Handle<String>();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001039 Handle<String> result = String::New(chars, size);
1040 delete[] chars;
1041 return result;
1042}
1043
1044
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001045#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001046i::Thread::Options SourceGroup::GetThreadOptions() {
1047 i::Thread::Options options;
1048 options.name = "IsolateThread";
1049 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1050 // which is not enough to parse the big literal expressions used in tests.
1051 // The stack size should be at least StackGuard::kLimitSize + some
1052 // OS-specific padding for thread startup code.
1053 options.stack_size = 2 << 20; // 2 Mb seems to be enough
1054 return options;
1055}
1056
1057
1058void SourceGroup::ExecuteInThread() {
1059 Isolate* isolate = Isolate::New();
1060 do {
1061 if (next_semaphore_ != NULL) next_semaphore_->Wait();
1062 {
1063 Isolate::Scope iscope(isolate);
1064 Locker lock(isolate);
1065 HandleScope scope;
1066 Persistent<Context> context = Shell::CreateEvaluationContext();
1067 {
1068 Context::Scope cscope(context);
1069 Execute();
1070 }
1071 context.Dispose();
1072 }
1073 if (done_semaphore_ != NULL) done_semaphore_->Signal();
1074 } while (!Shell::options.last_run);
1075 isolate->Dispose();
1076}
1077
1078
1079void SourceGroup::StartExecuteInThread() {
1080 if (thread_ == NULL) {
1081 thread_ = new IsolateThread(this);
1082 thread_->Start();
1083 }
1084 next_semaphore_->Signal();
1085}
1086
1087
1088void SourceGroup::WaitForThread() {
1089 if (thread_ == NULL) return;
1090 if (Shell::options.last_run) {
1091 thread_->Join();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001092 } else {
1093 done_semaphore_->Wait();
1094 }
1095}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001096#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001097
1098
1099bool Shell::SetOptions(int argc, char* argv[]) {
1100 for (int i = 0; i < argc; i++) {
1101 if (strcmp(argv[i], "--stress-opt") == 0) {
1102 options.stress_opt = true;
1103 argv[i] = NULL;
1104 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1105 options.stress_deopt = true;
1106 argv[i] = NULL;
1107 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1108 // No support for stressing if we can't use --always-opt.
1109 options.stress_opt = false;
1110 options.stress_deopt = false;
1111 } else if (strcmp(argv[i], "--shell") == 0) {
1112 options.interactive_shell = true;
1113 argv[i] = NULL;
1114 } else if (strcmp(argv[i], "--test") == 0) {
1115 options.test_shell = true;
1116 argv[i] = NULL;
1117 } else if (strcmp(argv[i], "--preemption") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001118#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001119 printf("D8 with shared library does not support multi-threading\n");
1120 return false;
1121#else
1122 options.use_preemption = true;
1123 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001124#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001125 } else if (strcmp(argv[i], "--no-preemption") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001126#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001127 printf("D8 with shared library does not support multi-threading\n");
1128 return false;
1129#else
1130 options.use_preemption = false;
1131 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001132#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001133 } else if (strcmp(argv[i], "--preemption-interval") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001134#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001135 printf("D8 with shared library does not support multi-threading\n");
1136 return false;
1137#else
1138 if (++i < argc) {
1139 argv[i-1] = NULL;
1140 char* end = NULL;
1141 options.preemption_interval = strtol(argv[i], &end, 10); // NOLINT
1142 if (options.preemption_interval <= 0
1143 || *end != '\0'
1144 || errno == ERANGE) {
1145 printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
1146 return false;
1147 }
1148 argv[i] = NULL;
1149 } else {
1150 printf("Missing value for --preemption-interval\n");
1151 return false;
1152 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001153#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001154 } else if (strcmp(argv[i], "-f") == 0) {
1155 // Ignore any -f flags for compatibility with other stand-alone
1156 // JavaScript engines.
1157 continue;
1158 } else if (strcmp(argv[i], "--isolate") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001159#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001160 printf("D8 with shared library does not support multi-threading\n");
1161 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001162#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001163 options.num_isolates++;
Ben Murdoch589d6972011-11-30 16:04:58 +00001164 } else if (strcmp(argv[i], "-p") == 0) {
1165#ifdef V8_SHARED
1166 printf("D8 with shared library does not support multi-threading\n");
1167 return false;
1168#else
1169 options.num_parallel_files++;
1170#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001171 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001172#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001173 else if (strcmp(argv[i], "--dump-counters") == 0) {
1174 printf("D8 with shared library does not include counters\n");
1175 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001176 } else if (strcmp(argv[i], "--debugger") == 0) {
1177 printf("Javascript debugger not included\n");
1178 return false;
1179 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001180#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001181 }
1182
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001183#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001184 // Run parallel threads if we are not using --isolate
Ben Murdoch589d6972011-11-30 16:04:58 +00001185 options.parallel_files = new char*[options.num_parallel_files];
1186 int parallel_files_set = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001187 for (int i = 1; i < argc; i++) {
1188 if (argv[i] == NULL) continue;
1189 if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
1190 if (options.num_isolates > 1) {
1191 printf("-p is not compatible with --isolate\n");
1192 return false;
1193 }
1194 argv[i] = NULL;
Ben Murdoch589d6972011-11-30 16:04:58 +00001195 i++;
1196 options.parallel_files[parallel_files_set] = argv[i];
1197 parallel_files_set++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001198 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001199 }
1200 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001201 if (parallel_files_set != options.num_parallel_files) {
1202 printf("-p requires a file containing a list of files as parameter\n");
1203 return false;
1204 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001205#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001206
1207 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1208
Ben Murdoch589d6972011-11-30 16:04:58 +00001209 // Set up isolated source groups.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001210 options.isolate_sources = new SourceGroup[options.num_isolates];
1211 SourceGroup* current = options.isolate_sources;
1212 current->Begin(argv, 1);
1213 for (int i = 1; i < argc; i++) {
1214 const char* str = argv[i];
1215 if (strcmp(str, "--isolate") == 0) {
1216 current->End(i);
1217 current++;
1218 current->Begin(argv, i + 1);
1219 } else if (strncmp(argv[i], "--", 2) == 0) {
1220 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
1221 }
1222 }
1223 current->End(argc);
1224
1225 return true;
1226}
1227
1228
1229int Shell::RunMain(int argc, char* argv[]) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001230#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001231 i::List<i::Thread*> threads(1);
Ben Murdoch589d6972011-11-30 16:04:58 +00001232 if (options.parallel_files != NULL) {
1233 for (int i = 0; i < options.num_parallel_files; i++) {
1234 char* files = NULL;
1235 { Locker lock(Isolate::GetCurrent());
1236 int size = 0;
1237 files = ReadChars(options.parallel_files[i], &size);
1238 }
1239 if (files == NULL) {
1240 printf("File list '%s' not found\n", options.parallel_files[i]);
1241 Exit(1);
1242 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001243 ShellThread* thread = new ShellThread(threads.length(), files);
1244 thread->Start();
1245 threads.Add(thread);
1246 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001247 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001248 for (int i = 1; i < options.num_isolates; ++i) {
1249 options.isolate_sources[i].StartExecuteInThread();
1250 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001251#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001252 { // NOLINT
1253 Locker lock;
1254 HandleScope scope;
1255 Persistent<Context> context = CreateEvaluationContext();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001256 {
1257 Context::Scope cscope(context);
1258 options.isolate_sources[0].Execute();
1259 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001260 if (options.last_run) {
1261 // Keep using the same context in the interactive shell
1262 evaluation_context_ = context;
1263 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001264 context.Dispose();
1265 }
1266
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001267#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001268 // Start preemption if threads have been created and preemption is enabled.
Ben Murdoch589d6972011-11-30 16:04:58 +00001269 if (threads.length() > 0
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001270 && options.use_preemption) {
1271 Locker::StartPreemption(options.preemption_interval);
1272 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001273#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001274 }
1275
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001276#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001277 for (int i = 1; i < options.num_isolates; ++i) {
1278 options.isolate_sources[i].WaitForThread();
1279 }
1280
Ben Murdoch589d6972011-11-30 16:04:58 +00001281 for (int i = 0; i < threads.length(); i++) {
1282 i::Thread* thread = threads[i];
1283 thread->Join();
1284 delete thread;
1285 }
1286
1287 if (threads.length() > 0 && options.use_preemption) {
1288 Locker lock;
1289 Locker::StopPreemption();
1290 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001291#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001292 return 0;
1293}
1294
1295
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001296int Shell::Main(int argc, char* argv[]) {
1297 if (!SetOptions(argc, argv)) return 1;
1298 Initialize();
1299
1300 int result = 0;
1301 if (options.stress_opt || options.stress_deopt) {
1302 Testing::SetStressRunType(
1303 options.stress_opt ? Testing::kStressTypeOpt
1304 : Testing::kStressTypeDeopt);
1305 int stress_runs = Testing::GetStressRuns();
1306 for (int i = 0; i < stress_runs && result == 0; i++) {
1307 printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
1308 Testing::PrepareStressRun(i);
1309 options.last_run = (i == stress_runs - 1);
1310 result = RunMain(argc, argv);
1311 }
1312 printf("======== Full Deoptimization =======\n");
1313 Testing::DeoptimizeAll();
1314 } else {
1315 result = RunMain(argc, argv);
1316 }
1317
1318
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001319#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001320 // Run remote debugger if requested, but never on --test
1321 if (i::FLAG_remote_debugger && !options.test_shell) {
1322 InstallUtilityScript();
1323 RunRemoteDebugger(i::FLAG_debugger_port);
1324 return 0;
1325 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001326#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001327
1328 // Run interactive shell if explicitly requested or if no script has been
1329 // executed, but never on --test
1330
1331 if (( options.interactive_shell
1332 || !options.script_executed )
1333 && !options.test_shell ) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001334#ifndef V8_SHARED
Ben Murdoch589d6972011-11-30 16:04:58 +00001335 InstallUtilityScript();
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001336#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001337 RunShell();
1338 }
1339
1340 V8::Dispose();
1341
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001342#ifndef V8_SHARED
1343 OnExit();
1344#endif // V8_SHARED
1345
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001346 return result;
1347}
1348
Steve Blocka7e24c12009-10-30 11:49:00 +00001349} // namespace v8
1350
1351
Ben Murdoch257744e2011-11-30 15:57:28 +00001352#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +00001353int main(int argc, char* argv[]) {
1354 return v8::Shell::Main(argc, argv);
1355}
Ben Murdoch257744e2011-11-30 15:57:28 +00001356#endif