blob: 63a7d157a9f7bbd619e7096129c0190e69b5075a [file] [log] [blame]
Ben Murdoch85b71792012-04-11 18:30:58 +01001// 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
Ben Murdoch85b71792012-04-11 18:30:58 +010069
70#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +000071LineEditor *LineEditor::first_ = NULL;
Ben Murdoch85b71792012-04-11 18:30:58 +010072const char* Shell::kHistoryFileName = ".d8_history";
73const 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 Murdoch85b71792012-04-11 18:30:58 +010099 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 Murdoch85b71792012-04-11 18:30:58 +0100106i::SmartArrayPointer<char> DumbLineEditor::Prompt(const char* prompt) {
107 static const int kBufferSize = 256;
108 char buffer[kBufferSize];
Steve Blocka7e24c12009-10-30 11:49:00 +0000109 printf("%s", prompt);
Ben Murdoch85b71792012-04-11 18:30:58 +0100110 char* str = fgets(buffer, kBufferSize, stdin);
111 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 Murdoch85b71792012-04-11 18:30:58 +0100121LineEditor* 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 Murdoch85b71792012-04-11 18:30:58 +0100149#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 Murdoch85b71792012-04-11 18:30:58 +0100153#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 Murdoch85b71792012-04-11 18:30:58 +0100181 fwrite(*str, sizeof(**str), str.length(), stdout);
Ben Murdoch589d6972011-11-30 16:04:58 +0000182 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
Ben Murdoch85b71792012-04-11 18:30:58 +0100240Handle<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 Murdoch85b71792012-04-11 18:30:58 +0100249 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
Ben Murdochc7cc0282012-03-05 14:35:55 +0000283
284Handle<Value> Shell::CreateExternalArray(const Arguments& args,
285 ExternalArrayType type,
286 size_t element_size) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000287 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 ||
288 element_size == 8);
Ben Murdoch85b71792012-04-11 18:30:58 +0100289 if (args.Length() != 1) {
Ben Murdochc7cc0282012-03-05 14:35:55 +0000290 return ThrowException(
Ben Murdoch85b71792012-04-11 18:30:58 +0100291 String::New("Array constructor needs one parameter."));
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000292 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100293 static const int kMaxLength = 0x3fffffff;
294#ifndef V8_SHARED
295 ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
296#endif // V8_SHARED
297 size_t length = 0;
298 if (args[0]->IsUint32()) {
299 length = args[0]->Uint32Value();
300 } 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();
306 if (raw_length < 0) {
307 return ThrowException(String::New("Array length must not be negative."));
308 }
309 if (raw_length > static_cast<int32_t>(kMaxLength)) {
310 return ThrowException(
311 String::New("Array length exceeds maximum length."));
312 }
313 length = static_cast<size_t>(raw_length);
Ben Murdochc7cc0282012-03-05 14:35:55 +0000314 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100315 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 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000322 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 Murdoch85b71792012-04-11 18:30:58 +0100326 array->SetIndexedPropertiesToExternalArrayData(data, type,
327 static_cast<int>(length));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000328 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) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100337 free(data);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000338 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();
Ben Murdoch85b71792012-04-11 18:30:58 +0100763
764 v8::TryCatch try_catch;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000765 Persistent<Context> context = Context::New(NULL, global_template);
Ben Murdoch85b71792012-04-11 18:30:58 +0100766 if (context.IsEmpty()) {
767 v8::Local<v8::Value> st = try_catch.StackTrace();
768 ASSERT(!context.IsEmpty());
769 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000770 Context::Scope scope(context);
771
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000772#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000773 i::JSArguments js_args = i::FLAG_js_arguments;
774 i::Handle<i::FixedArray> arguments_array =
775 FACTORY->NewFixedArray(js_args.argc());
776 for (int j = 0; j < js_args.argc(); j++) {
777 i::Handle<i::String> arg =
778 FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
779 arguments_array->set(j, *arg);
780 }
781 i::Handle<i::JSArray> arguments_jsarray =
782 FACTORY->NewJSArrayWithElements(arguments_array);
783 context->Global()->Set(String::New("arguments"),
784 Utils::ToLocal(arguments_jsarray));
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000785#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000786 return context;
787}
788
789
Ben Murdoch589d6972011-11-30 16:04:58 +0000790void Shell::Exit(int exit_code) {
791 // Use _exit instead of exit to avoid races between isolate
792 // threads and static destructors.
793 fflush(stdout);
794 fflush(stderr);
795 _exit(exit_code);
796}
797
798
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000799#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000800void Shell::OnExit() {
Ben Murdoch589d6972011-11-30 16:04:58 +0000801 if (console != NULL) console->Close();
Steve Blocka7e24c12009-10-30 11:49:00 +0000802 if (i::FLAG_dump_counters) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100803 printf("+----------------------------------------+-------------+\n");
804 printf("| Name | Value |\n");
805 printf("+----------------------------------------+-------------+\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000806 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100807 Counter* counter = i.CurrentValue();
Steve Blocka7e24c12009-10-30 11:49:00 +0000808 if (counter->is_histogram()) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100809 printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
810 printf("| t:%-36s | %11i |\n", i.CurrentKey(), counter->sample_total());
Steve Blocka7e24c12009-10-30 11:49:00 +0000811 } else {
Ben Murdoch85b71792012-04-11 18:30:58 +0100812 printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
Steve Blocka7e24c12009-10-30 11:49:00 +0000813 }
814 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100815 printf("+----------------------------------------+-------------+\n");
Steve Blocka7e24c12009-10-30 11:49:00 +0000816 }
817 if (counters_file_ != NULL)
818 delete counters_file_;
819}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000820#endif // V8_SHARED
821
822
823static FILE* FOpen(const char* path, const char* mode) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100824#if (defined(_WIN32) || defined(_WIN64))
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000825 FILE* result;
826 if (fopen_s(&result, path, mode) == 0) {
827 return result;
828 } else {
829 return NULL;
830 }
831#else
832 FILE* file = fopen(path, mode);
833 if (file == NULL) return NULL;
834 struct stat file_stat;
835 if (fstat(fileno(file), &file_stat) != 0) return NULL;
836 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
837 if (is_regular_file) return file;
838 fclose(file);
839 return NULL;
840#endif
841}
Steve Blocka7e24c12009-10-30 11:49:00 +0000842
843
844static char* ReadChars(const char* name, int* size_out) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000845 // Release the V8 lock while reading files.
846 v8::Unlocker unlocker(Isolate::GetCurrent());
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000847 FILE* file = FOpen(name, "rb");
Steve Blocka7e24c12009-10-30 11:49:00 +0000848 if (file == NULL) return NULL;
849
850 fseek(file, 0, SEEK_END);
851 int size = ftell(file);
852 rewind(file);
853
854 char* chars = new char[size + 1];
855 chars[size] = '\0';
856 for (int i = 0; i < size;) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000857 int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
Steve Blocka7e24c12009-10-30 11:49:00 +0000858 i += read;
859 }
860 fclose(file);
861 *size_out = size;
862 return chars;
863}
864
865
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000866#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000867static char* ReadToken(char* data, char token) {
868 char* next = i::OS::StrChr(data, token);
869 if (next != NULL) {
870 *next = '\0';
871 return (next + 1);
872 }
873
874 return NULL;
875}
876
877
878static char* ReadLine(char* data) {
879 return ReadToken(data, '\n');
880}
881
882
883static char* ReadWord(char* data) {
884 return ReadToken(data, ' ');
885}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000886#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000887
888
889// Reads a file into a v8 string.
890Handle<String> Shell::ReadFile(const char* name) {
891 int size = 0;
892 char* chars = ReadChars(name, &size);
893 if (chars == NULL) return Handle<String>();
894 Handle<String> result = String::New(chars);
895 delete[] chars;
896 return result;
897}
898
899
900void Shell::RunShell() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000901 Locker locker;
902 Context::Scope context_scope(evaluation_context_);
Ben Murdoch589d6972011-11-30 16:04:58 +0000903 HandleScope outer_scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000904 Handle<String> name = String::New("(d8)");
Ben Murdoch85b71792012-04-11 18:30:58 +0100905#ifndef V8_SHARED
Ben Murdoch589d6972011-11-30 16:04:58 +0000906 console = LineEditor::Get();
907 printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
Ben Murdoch85b71792012-04-11 18:30:58 +0100908 if (i::FLAG_debugger) {
909 printf("JavaScript debugger enabled\n");
910 }
Ben Murdoch589d6972011-11-30 16:04:58 +0000911 console->Open();
Steve Blocka7e24c12009-10-30 11:49:00 +0000912 while (true) {
Ben Murdoch85b71792012-04-11 18:30:58 +0100913 i::SmartArrayPointer<char> input = console->Prompt(Shell::kPrompt);
914 if (input.is_empty()) break;
915 console->AddHistory(*input);
Ben Murdoch589d6972011-11-30 16:04:58 +0000916 HandleScope inner_scope;
Ben Murdoch85b71792012-04-11 18:30:58 +0100917 ExecuteString(String::New(*input), name, true, true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000918 }
Ben Murdoch85b71792012-04-11 18:30:58 +0100919#else
920 printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion());
921 static const int kBufferSize = 256;
922 while (true) {
923 char buffer[kBufferSize];
924 printf("%s", Shell::kPrompt);
925 if (fgets(buffer, kBufferSize, stdin) == NULL) break;
926 HandleScope inner_scope;
927 ExecuteString(String::New(buffer), name, true, true);
928 }
929#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000930 printf("\n");
931}
932
933
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000934#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000935class ShellThread : public i::Thread {
936 public:
Ben Murdoch589d6972011-11-30 16:04:58 +0000937 // Takes ownership of the underlying char array of |files|.
938 ShellThread(int no, char* files)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000939 : Thread("d8:ShellThread"),
940 no_(no), files_(files) { }
Ben Murdoch589d6972011-11-30 16:04:58 +0000941
942 ~ShellThread() {
943 delete[] files_;
944 }
945
Steve Blocka7e24c12009-10-30 11:49:00 +0000946 virtual void Run();
947 private:
948 int no_;
Ben Murdoch589d6972011-11-30 16:04:58 +0000949 char* files_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000950};
951
952
953void ShellThread::Run() {
Ben Murdoch589d6972011-11-30 16:04:58 +0000954 char* ptr = files_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000955 while ((ptr != NULL) && (*ptr != '\0')) {
956 // For each newline-separated line.
957 char* next_line = ReadLine(ptr);
958
959 if (*ptr == '#') {
960 // Skip comment lines.
961 ptr = next_line;
962 continue;
963 }
964
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000965 // Prepare the context for this thread.
966 Locker locker;
Ben Murdoch589d6972011-11-30 16:04:58 +0000967 HandleScope outer_scope;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000968 Persistent<Context> thread_context = Shell::CreateEvaluationContext();
Steve Blocka7e24c12009-10-30 11:49:00 +0000969 Context::Scope context_scope(thread_context);
970
971 while ((ptr != NULL) && (*ptr != '\0')) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000972 HandleScope inner_scope;
Steve Blocka7e24c12009-10-30 11:49:00 +0000973 char* filename = ptr;
974 ptr = ReadWord(ptr);
975
976 // Skip empty strings.
977 if (strlen(filename) == 0) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000978 continue;
Steve Blocka7e24c12009-10-30 11:49:00 +0000979 }
980
981 Handle<String> str = Shell::ReadFile(filename);
982 if (str.IsEmpty()) {
Ben Murdoch589d6972011-11-30 16:04:58 +0000983 printf("File '%s' not found\n", filename);
984 Shell::Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000985 }
986
987 Shell::ExecuteString(str, String::New(filename), false, false);
988 }
989
990 thread_context.Dispose();
991 ptr = next_line;
992 }
993}
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000994#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +0000995
996
Ben Murdoch589d6972011-11-30 16:04:58 +0000997SourceGroup::~SourceGroup() {
998#ifndef V8_SHARED
999 delete next_semaphore_;
1000 next_semaphore_ = NULL;
1001 delete done_semaphore_;
1002 done_semaphore_ = NULL;
1003 delete thread_;
1004 thread_ = NULL;
1005#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001006}
Steve Blocka7e24c12009-10-30 11:49:00 +00001007
Steve Blocka7e24c12009-10-30 11:49:00 +00001008
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001009void SourceGroup::Execute() {
1010 for (int i = begin_offset_; i < end_offset_; ++i) {
1011 const char* arg = argv_[i];
1012 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1013 // Execute argument given to -e option directly.
1014 HandleScope handle_scope;
1015 Handle<String> file_name = String::New("unnamed");
1016 Handle<String> source = String::New(argv_[i + 1]);
1017 if (!Shell::ExecuteString(source, file_name, false, true)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001018 Shell::Exit(1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001019 }
1020 ++i;
1021 } else if (arg[0] == '-') {
1022 // Ignore other options. They have been parsed already.
1023 } else {
1024 // Use all other arguments as names of files to load and run.
1025 HandleScope handle_scope;
1026 Handle<String> file_name = String::New(arg);
1027 Handle<String> source = ReadFile(arg);
1028 if (source.IsEmpty()) {
1029 printf("Error reading '%s'\n", arg);
Ben Murdoch589d6972011-11-30 16:04:58 +00001030 Shell::Exit(1);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001031 }
1032 if (!Shell::ExecuteString(source, file_name, false, true)) {
Ben Murdoch589d6972011-11-30 16:04:58 +00001033 Shell::Exit(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001034 }
1035 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001036 }
1037}
Steve Blocka7e24c12009-10-30 11:49:00 +00001038
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001039
1040Handle<String> SourceGroup::ReadFile(const char* name) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001041 int size;
1042 const char* chars = ReadChars(name, &size);
1043 if (chars == NULL) return Handle<String>();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001044 Handle<String> result = String::New(chars, size);
1045 delete[] chars;
1046 return result;
1047}
1048
1049
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001050#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001051i::Thread::Options SourceGroup::GetThreadOptions() {
Ben Murdoch85b71792012-04-11 18:30:58 +01001052 i::Thread::Options options;
1053 options.name = "IsolateThread";
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001054 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1055 // which is not enough to parse the big literal expressions used in tests.
1056 // The stack size should be at least StackGuard::kLimitSize + some
Ben Murdoch85b71792012-04-11 18:30:58 +01001057 // OS-specific padding for thread startup code.
1058 options.stack_size = 2 << 20; // 2 Mb seems to be enough
1059 return options;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001060}
1061
1062
1063void SourceGroup::ExecuteInThread() {
1064 Isolate* isolate = Isolate::New();
1065 do {
1066 if (next_semaphore_ != NULL) next_semaphore_->Wait();
1067 {
1068 Isolate::Scope iscope(isolate);
1069 Locker lock(isolate);
1070 HandleScope scope;
1071 Persistent<Context> context = Shell::CreateEvaluationContext();
1072 {
1073 Context::Scope cscope(context);
1074 Execute();
1075 }
1076 context.Dispose();
1077 }
1078 if (done_semaphore_ != NULL) done_semaphore_->Signal();
1079 } while (!Shell::options.last_run);
1080 isolate->Dispose();
1081}
1082
1083
1084void SourceGroup::StartExecuteInThread() {
1085 if (thread_ == NULL) {
1086 thread_ = new IsolateThread(this);
1087 thread_->Start();
1088 }
1089 next_semaphore_->Signal();
1090}
1091
1092
1093void SourceGroup::WaitForThread() {
1094 if (thread_ == NULL) return;
1095 if (Shell::options.last_run) {
1096 thread_->Join();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001097 } else {
1098 done_semaphore_->Wait();
1099 }
1100}
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001101#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001102
1103
1104bool Shell::SetOptions(int argc, char* argv[]) {
1105 for (int i = 0; i < argc; i++) {
1106 if (strcmp(argv[i], "--stress-opt") == 0) {
1107 options.stress_opt = true;
1108 argv[i] = NULL;
1109 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1110 options.stress_deopt = true;
1111 argv[i] = NULL;
1112 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1113 // No support for stressing if we can't use --always-opt.
1114 options.stress_opt = false;
1115 options.stress_deopt = false;
1116 } else if (strcmp(argv[i], "--shell") == 0) {
1117 options.interactive_shell = true;
1118 argv[i] = NULL;
1119 } else if (strcmp(argv[i], "--test") == 0) {
1120 options.test_shell = true;
1121 argv[i] = NULL;
1122 } else if (strcmp(argv[i], "--preemption") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001123#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001124 printf("D8 with shared library does not support multi-threading\n");
1125 return false;
1126#else
1127 options.use_preemption = true;
1128 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001129#endif // V8_SHARED
Ben Murdoch85b71792012-04-11 18:30:58 +01001130 } else if (strcmp(argv[i], "--no-preemption") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001131#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001132 printf("D8 with shared library does not support multi-threading\n");
1133 return false;
1134#else
1135 options.use_preemption = false;
1136 argv[i] = NULL;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001137#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001138 } else if (strcmp(argv[i], "--preemption-interval") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001139#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001140 printf("D8 with shared library does not support multi-threading\n");
1141 return false;
1142#else
1143 if (++i < argc) {
1144 argv[i-1] = NULL;
1145 char* end = NULL;
1146 options.preemption_interval = strtol(argv[i], &end, 10); // NOLINT
1147 if (options.preemption_interval <= 0
1148 || *end != '\0'
1149 || errno == ERANGE) {
1150 printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
1151 return false;
1152 }
1153 argv[i] = NULL;
1154 } else {
1155 printf("Missing value for --preemption-interval\n");
1156 return false;
1157 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001158#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001159 } else if (strcmp(argv[i], "-f") == 0) {
1160 // Ignore any -f flags for compatibility with other stand-alone
1161 // JavaScript engines.
1162 continue;
1163 } else if (strcmp(argv[i], "--isolate") == 0) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001164#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001165 printf("D8 with shared library does not support multi-threading\n");
1166 return false;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001167#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001168 options.num_isolates++;
Ben Murdoch589d6972011-11-30 16:04:58 +00001169 } else if (strcmp(argv[i], "-p") == 0) {
1170#ifdef V8_SHARED
1171 printf("D8 with shared library does not support multi-threading\n");
1172 return false;
1173#else
1174 options.num_parallel_files++;
1175#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001176 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001177#ifdef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001178 else if (strcmp(argv[i], "--dump-counters") == 0) {
1179 printf("D8 with shared library does not include counters\n");
1180 return false;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001181 } else if (strcmp(argv[i], "--debugger") == 0) {
1182 printf("Javascript debugger not included\n");
1183 return false;
1184 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001185#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001186 }
1187
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001188#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001189 // Run parallel threads if we are not using --isolate
Ben Murdoch589d6972011-11-30 16:04:58 +00001190 options.parallel_files = new char*[options.num_parallel_files];
1191 int parallel_files_set = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001192 for (int i = 1; i < argc; i++) {
1193 if (argv[i] == NULL) continue;
1194 if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
1195 if (options.num_isolates > 1) {
1196 printf("-p is not compatible with --isolate\n");
1197 return false;
1198 }
1199 argv[i] = NULL;
Ben Murdoch589d6972011-11-30 16:04:58 +00001200 i++;
1201 options.parallel_files[parallel_files_set] = argv[i];
1202 parallel_files_set++;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001203 argv[i] = NULL;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001204 }
1205 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001206 if (parallel_files_set != options.num_parallel_files) {
1207 printf("-p requires a file containing a list of files as parameter\n");
1208 return false;
1209 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001210#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001211
1212 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1213
Ben Murdoch589d6972011-11-30 16:04:58 +00001214 // Set up isolated source groups.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001215 options.isolate_sources = new SourceGroup[options.num_isolates];
1216 SourceGroup* current = options.isolate_sources;
1217 current->Begin(argv, 1);
1218 for (int i = 1; i < argc; i++) {
1219 const char* str = argv[i];
1220 if (strcmp(str, "--isolate") == 0) {
1221 current->End(i);
1222 current++;
1223 current->Begin(argv, i + 1);
1224 } else if (strncmp(argv[i], "--", 2) == 0) {
1225 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
1226 }
1227 }
1228 current->End(argc);
1229
1230 return true;
1231}
1232
1233
1234int Shell::RunMain(int argc, char* argv[]) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001235#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001236 i::List<i::Thread*> threads(1);
Ben Murdoch589d6972011-11-30 16:04:58 +00001237 if (options.parallel_files != NULL) {
1238 for (int i = 0; i < options.num_parallel_files; i++) {
1239 char* files = NULL;
1240 { Locker lock(Isolate::GetCurrent());
1241 int size = 0;
1242 files = ReadChars(options.parallel_files[i], &size);
1243 }
1244 if (files == NULL) {
1245 printf("File list '%s' not found\n", options.parallel_files[i]);
1246 Exit(1);
1247 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001248 ShellThread* thread = new ShellThread(threads.length(), files);
1249 thread->Start();
1250 threads.Add(thread);
1251 }
Ben Murdoch589d6972011-11-30 16:04:58 +00001252 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001253 for (int i = 1; i < options.num_isolates; ++i) {
1254 options.isolate_sources[i].StartExecuteInThread();
1255 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001256#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001257 { // NOLINT
1258 Locker lock;
1259 HandleScope scope;
1260 Persistent<Context> context = CreateEvaluationContext();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001261 {
1262 Context::Scope cscope(context);
1263 options.isolate_sources[0].Execute();
1264 }
Ben Murdoch85b71792012-04-11 18:30:58 +01001265 if (options.last_run) {
1266 // Keep using the same context in the interactive shell
1267 evaluation_context_ = context;
1268 } else {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001269 context.Dispose();
1270 }
1271
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001272#ifndef V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001273 // Start preemption if threads have been created and preemption is enabled.
Ben Murdoch589d6972011-11-30 16:04:58 +00001274 if (threads.length() > 0
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001275 && options.use_preemption) {
1276 Locker::StartPreemption(options.preemption_interval);
1277 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001278#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001279 }
1280
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001281#ifndef V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001282 for (int i = 1; i < options.num_isolates; ++i) {
1283 options.isolate_sources[i].WaitForThread();
1284 }
1285
Ben Murdoch589d6972011-11-30 16:04:58 +00001286 for (int i = 0; i < threads.length(); i++) {
1287 i::Thread* thread = threads[i];
1288 thread->Join();
1289 delete thread;
1290 }
1291
1292 if (threads.length() > 0 && options.use_preemption) {
1293 Locker lock;
1294 Locker::StopPreemption();
1295 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001296#endif // V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +00001297 return 0;
1298}
1299
1300
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001301int Shell::Main(int argc, char* argv[]) {
1302 if (!SetOptions(argc, argv)) return 1;
1303 Initialize();
1304
1305 int result = 0;
1306 if (options.stress_opt || options.stress_deopt) {
1307 Testing::SetStressRunType(
1308 options.stress_opt ? Testing::kStressTypeOpt
1309 : Testing::kStressTypeDeopt);
1310 int stress_runs = Testing::GetStressRuns();
1311 for (int i = 0; i < stress_runs && result == 0; i++) {
1312 printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
1313 Testing::PrepareStressRun(i);
1314 options.last_run = (i == stress_runs - 1);
1315 result = RunMain(argc, argv);
1316 }
1317 printf("======== Full Deoptimization =======\n");
1318 Testing::DeoptimizeAll();
1319 } else {
1320 result = RunMain(argc, argv);
1321 }
1322
1323
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001324#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001325 // Run remote debugger if requested, but never on --test
1326 if (i::FLAG_remote_debugger && !options.test_shell) {
1327 InstallUtilityScript();
1328 RunRemoteDebugger(i::FLAG_debugger_port);
1329 return 0;
1330 }
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001331#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001332
1333 // Run interactive shell if explicitly requested or if no script has been
1334 // executed, but never on --test
1335
1336 if (( options.interactive_shell
1337 || !options.script_executed )
1338 && !options.test_shell ) {
Ben Murdoch85b71792012-04-11 18:30:58 +01001339#ifndef V8_SHARED
1340 InstallUtilityScript();
1341#endif // V8_SHARED
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001342 RunShell();
1343 }
1344
1345 V8::Dispose();
1346
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001347#ifndef V8_SHARED
1348 OnExit();
1349#endif // V8_SHARED
1350
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001351 return result;
1352}
1353
Steve Blocka7e24c12009-10-30 11:49:00 +00001354} // namespace v8
1355
1356
Ben Murdoch257744e2011-11-30 15:57:28 +00001357#ifndef GOOGLE3
Steve Blocka7e24c12009-10-30 11:49:00 +00001358int main(int argc, char* argv[]) {
1359 return v8::Shell::Main(argc, argv);
1360}
Ben Murdoch257744e2011-11-30 15:57:28 +00001361#endif