blob: 780b0c0716e5d8b0dd4fc86197dc84fa0810d0ba [file] [log] [blame]
ager@chromium.org04921a82011-06-27 13:21:41 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000029#ifdef USING_V8_SHARED // Defined when linking against shared lib on Windows.
30#define V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000031#endif
32
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000033#ifdef COMPRESS_STARTUP_DATA_BZ2
34#include <bzlib.h>
35#endif
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000036
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000037#include <errno.h>
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000038#include <stdlib.h>
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000039#include <string.h>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000040#include <sys/stat.h>
ager@chromium.orga74f0da2008-12-03 16:05:52 +000041
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000042#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000043#include <assert.h>
44#include "../include/v8-testing.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000045#endif // V8_SHARED
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000046
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000047#include "d8.h"
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000048
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000049#ifndef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000050#include "api.h"
51#include "checks.h"
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000052#include "d8-debug.h"
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000053#include "debug.h"
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000054#include "natives.h"
ager@chromium.orgddb913d2009-01-27 10:01:48 +000055#include "platform.h"
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000056#include "v8.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000057#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000058
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000059#if !defined(_WIN32) && !defined(_WIN64)
60#include <unistd.h> // NOLINT
61#endif
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000062
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000063#ifndef ASSERT
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000064#define ASSERT(condition) assert(condition)
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000065#endif
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000066
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000067namespace v8 {
68
69
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000070#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000071LineEditor *LineEditor::first_ = NULL;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000072const char* Shell::kHistoryFileName = ".d8_history";
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000073
74
75LineEditor::LineEditor(Type type, const char* name)
76 : type_(type),
77 name_(name),
78 next_(first_) {
79 first_ = this;
80}
81
82
83LineEditor* LineEditor::Get() {
84 LineEditor* current = first_;
85 LineEditor* best = current;
86 while (current != NULL) {
87 if (current->type_ > best->type_)
88 best = current;
89 current = current->next_;
90 }
91 return best;
92}
93
94
95class DumbLineEditor: public LineEditor {
96 public:
97 DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
98 virtual i::SmartPointer<char> Prompt(const char* prompt);
99};
100
101
102static DumbLineEditor dumb_line_editor;
103
104
105i::SmartPointer<char> DumbLineEditor::Prompt(const char* prompt) {
106 static const int kBufferSize = 256;
107 char buffer[kBufferSize];
108 printf("%s", prompt);
109 char* str = fgets(buffer, kBufferSize, stdin);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000110 return i::SmartPointer<char>(str ? i::StrDup(str) : str);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000111}
112
113
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000114CounterMap* Shell::counter_map_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000115i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
116CounterCollection Shell::local_counters_;
117CounterCollection* Shell::counters_ = &local_counters_;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000118i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000119Persistent<Context> Shell::utility_context_;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000120#endif // V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000121
122Persistent<Context> Shell::evaluation_context_;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000123ShellOptions Shell::options;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000124const char* Shell::kPrompt = "d8> ";
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000125
126
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000127#ifndef V8_SHARED
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000128bool CounterMap::Match(void* key1, void* key2) {
129 const char* name1 = reinterpret_cast<const char*>(key1);
130 const char* name2 = reinterpret_cast<const char*>(key2);
131 return strcmp(name1, name2) == 0;
132}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000133#endif // V8_SHARED
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000134
135
iposva@chromium.org245aa852009-02-10 00:49:54 +0000136// Converts a V8 value to a C string.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000137const char* Shell::ToCString(const v8::String::Utf8Value& value) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000138 return *value ? *value : "<string conversion failed>";
139}
140
141
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000142// Executes a string within the current v8 context.
143bool Shell::ExecuteString(Handle<String> source,
144 Handle<Value> name,
145 bool print_result,
146 bool report_exceptions) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000147#ifndef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000148 bool FLAG_debugger = i::FLAG_debugger;
149#else
150 bool FLAG_debugger = false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000151#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000152 HandleScope handle_scope;
153 TryCatch try_catch;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000154 options.script_executed = true;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000155 if (FLAG_debugger) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000156 // When debugging make exceptions appear to be uncaught.
157 try_catch.SetVerbose(true);
158 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000159 Handle<Script> script = Script::Compile(source, name);
160 if (script.IsEmpty()) {
161 // Print errors that happened during compilation.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000162 if (report_exceptions && !FLAG_debugger)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000163 ReportException(&try_catch);
164 return false;
165 } else {
166 Handle<Value> result = script->Run();
167 if (result.IsEmpty()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000168 ASSERT(try_catch.HasCaught());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000169 // Print errors that happened during execution.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000170 if (report_exceptions && !FLAG_debugger)
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000171 ReportException(&try_catch);
172 return false;
173 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +0000174 ASSERT(!try_catch.HasCaught());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000175 if (print_result && !result->IsUndefined()) {
176 // If all went well and the result wasn't undefined then print
177 // the returned value.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000178 v8::String::Utf8Value str(result);
179 const char* cstr = ToCString(str);
180 printf("%s\n", cstr);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000181 }
182 return true;
183 }
184 }
185}
186
187
188Handle<Value> Shell::Print(const Arguments& args) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000189 Handle<Value> val = Write(args);
190 printf("\n");
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000191 fflush(stdout);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000192 return val;
193}
194
195
196Handle<Value> Shell::Write(const Arguments& args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000197 for (int i = 0; i < args.Length(); i++) {
198 HandleScope handle_scope;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000199 if (i != 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000200 printf(" ");
201 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000202 v8::String::Utf8Value str(args[i]);
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000203 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000204 if (n != str.length()) {
205 printf("Error in fwrite\n");
206 exit(1);
207 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000208 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000209 return Undefined();
210}
211
212
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000213Handle<Value> Shell::Read(const Arguments& args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000214 String::Utf8Value file(args[0]);
215 if (*file == NULL) {
216 return ThrowException(String::New("Error loading file"));
217 }
218 Handle<String> source = ReadFile(*file);
219 if (source.IsEmpty()) {
220 return ThrowException(String::New("Error loading file"));
221 }
222 return source;
223}
224
225
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000226Handle<Value> Shell::ReadLine(const Arguments& args) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000227 static const int kBufferSize = 256;
228 char buffer[kBufferSize];
229 Handle<String> accumulator = String::New("");
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000230 int length;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +0000231 while (true) {
232 // Continue reading if the line ends with an escape '\\' or the line has
233 // not been fully read into the buffer yet (does not end with '\n').
234 // If fgets gets an error, just give up.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000235 if (fgets(buffer, kBufferSize, stdin) == NULL) return Null();
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000236 length = static_cast<int>(strlen(buffer));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +0000237 if (length == 0) {
238 return accumulator;
239 } else if (buffer[length-1] != '\n') {
240 accumulator = String::Concat(accumulator, String::New(buffer, length));
241 } else if (length > 1 && buffer[length-2] == '\\') {
242 buffer[length-2] = '\n';
243 accumulator = String::Concat(accumulator, String::New(buffer, length-1));
244 } else {
245 return String::Concat(accumulator, String::New(buffer, length-1));
246 }
247 }
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000248}
249
250
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000251Handle<Value> Shell::Load(const Arguments& args) {
252 for (int i = 0; i < args.Length(); i++) {
253 HandleScope handle_scope;
254 String::Utf8Value file(args[i]);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000255 if (*file == NULL) {
256 return ThrowException(String::New("Error loading file"));
257 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000258 Handle<String> source = ReadFile(*file);
259 if (source.IsEmpty()) {
260 return ThrowException(String::New("Error loading file"));
261 }
262 if (!ExecuteString(source, String::New(*file), false, false)) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000263 return ThrowException(String::New("Error executing file"));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000264 }
265 }
266 return Undefined();
267}
268
269
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000270Handle<Value> Shell::CreateExternalArray(const Arguments& args,
271 ExternalArrayType type,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000272 size_t element_size) {
273 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 ||
274 element_size == 8);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000275 if (args.Length() != 1) {
276 return ThrowException(
277 String::New("Array constructor needs one parameter."));
278 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000279 static const int kMaxLength = 0x3fffffff;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000280#ifndef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000281 ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000282#endif // V8_SHARED
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000283 size_t length = 0;
284 if (args[0]->IsUint32()) {
285 length = args[0]->Uint32Value();
286 } else if (args[0]->IsNumber()) {
287 double raw_length = args[0]->NumberValue();
288 if (raw_length < 0) {
289 return ThrowException(String::New("Array length must not be negative."));
290 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000291 if (raw_length > kMaxLength) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000292 return ThrowException(
293 String::New("Array length exceeds maximum length."));
294 }
295 length = static_cast<size_t>(raw_length);
296 } else {
297 return ThrowException(String::New("Array length must be a number."));
298 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000299 if (length > static_cast<size_t>(kMaxLength)) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000300 return ThrowException(String::New("Array length exceeds maximum length."));
301 }
302 void* data = calloc(length, element_size);
303 if (data == NULL) {
304 return ThrowException(String::New("Memory allocation failed."));
305 }
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000306 Handle<Object> array = Object::New();
307 Persistent<Object> persistent_array = Persistent<Object>::New(array);
308 persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
309 persistent_array.MarkIndependent();
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000310 array->SetIndexedPropertiesToExternalArrayData(data, type,
311 static_cast<int>(length));
312 array->Set(String::New("length"),
313 Int32::New(static_cast<int32_t>(length)), ReadOnly);
314 array->Set(String::New("BYTES_PER_ELEMENT"),
315 Int32::New(static_cast<int32_t>(element_size)));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000316 return array;
317}
318
319
320void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
321 free(data);
322 object.Dispose();
323}
324
325
326Handle<Value> Shell::Int8Array(const Arguments& args) {
327 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
328}
329
330
331Handle<Value> Shell::Uint8Array(const Arguments& args) {
332 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t));
333}
334
335
336Handle<Value> Shell::Int16Array(const Arguments& args) {
337 return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t));
338}
339
340
341Handle<Value> Shell::Uint16Array(const Arguments& args) {
342 return CreateExternalArray(args, kExternalUnsignedShortArray,
343 sizeof(uint16_t));
344}
345
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000346
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000347Handle<Value> Shell::Int32Array(const Arguments& args) {
348 return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t));
349}
350
351
352Handle<Value> Shell::Uint32Array(const Arguments& args) {
353 return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t));
354}
355
356
357Handle<Value> Shell::Float32Array(const Arguments& args) {
358 return CreateExternalArray(args, kExternalFloatArray,
359 sizeof(float)); // NOLINT
360}
361
362
363Handle<Value> Shell::Float64Array(const Arguments& args) {
364 return CreateExternalArray(args, kExternalDoubleArray,
365 sizeof(double)); // NOLINT
366}
367
368
369Handle<Value> Shell::PixelArray(const Arguments& args) {
370 return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t));
371}
372
373
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000374Handle<Value> Shell::Yield(const Arguments& args) {
375 v8::Unlocker unlocker;
376 return Undefined();
377}
378
379
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000380Handle<Value> Shell::Quit(const Arguments& args) {
381 int exit_code = args[0]->Int32Value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000382#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000383 OnExit();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000384#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000385 exit(exit_code);
386 return Undefined();
387}
388
389
390Handle<Value> Shell::Version(const Arguments& args) {
391 return String::New(V8::GetVersion());
392}
393
394
395void Shell::ReportException(v8::TryCatch* try_catch) {
396 HandleScope handle_scope;
iposva@chromium.org245aa852009-02-10 00:49:54 +0000397 v8::String::Utf8Value exception(try_catch->Exception());
398 const char* exception_string = ToCString(exception);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000399 Handle<Message> message = try_catch->Message();
400 if (message.IsEmpty()) {
401 // V8 didn't provide any extra information about this error; just
402 // print the exception.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000403 printf("%s\n", exception_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000404 } else {
405 // Print (filename):(line number): (message).
iposva@chromium.org245aa852009-02-10 00:49:54 +0000406 v8::String::Utf8Value filename(message->GetScriptResourceName());
407 const char* filename_string = ToCString(filename);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000408 int linenum = message->GetLineNumber();
iposva@chromium.org245aa852009-02-10 00:49:54 +0000409 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000410 // Print line of source code.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000411 v8::String::Utf8Value sourceline(message->GetSourceLine());
412 const char* sourceline_string = ToCString(sourceline);
413 printf("%s\n", sourceline_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000414 // Print wavy underline (GetUnderline is deprecated).
415 int start = message->GetStartColumn();
416 for (int i = 0; i < start; i++) {
417 printf(" ");
418 }
419 int end = message->GetEndColumn();
420 for (int i = start; i < end; i++) {
421 printf("^");
422 }
423 printf("\n");
danno@chromium.org40cb8782011-05-25 07:58:50 +0000424 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
425 if (stack_trace.length() > 0) {
426 const char* stack_trace_string = ToCString(stack_trace);
427 printf("%s\n", stack_trace_string);
428 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000429 }
430}
431
432
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000433#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000434Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
435 HandleScope handle_scope;
436 Context::Scope context_scope(utility_context_);
437 Handle<Object> global = utility_context_->Global();
438 Handle<Value> fun = global->Get(String::New("GetCompletions"));
439 static const int kArgc = 3;
440 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
441 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
442 return handle_scope.Close(Handle<Array>::Cast(val));
443}
444
445
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000446#ifdef ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000447Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000448 Context::Scope context_scope(utility_context_);
449 Handle<Object> global = utility_context_->Global();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000450 Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000451 static const int kArgc = 1;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000452 Handle<Value> argv[kArgc] = { message };
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000453 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000454 return Handle<Object>::Cast(val);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000455}
456
457
458Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
459 Context::Scope context_scope(utility_context_);
460 Handle<Object> global = utility_context_->Global();
461 Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
462 static const int kArgc = 1;
463 Handle<Value> argv[kArgc] = { command };
464 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
465 return val;
466}
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000467#endif // ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000468#endif // V8_SHARED
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000469
470
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000471#ifndef V8_SHARED
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000472int32_t* Counter::Bind(const char* name, bool is_histogram) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000473 int i;
474 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
475 name_[i] = static_cast<char>(name[i]);
476 name_[i] = '\0';
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000477 is_histogram_ = is_histogram;
478 return ptr();
479}
480
481
482void Counter::AddSample(int32_t sample) {
483 count_++;
484 sample_total_ += sample;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000485}
486
487
488CounterCollection::CounterCollection() {
489 magic_number_ = 0xDEADFACE;
490 max_counters_ = kMaxCounters;
491 max_name_size_ = Counter::kMaxNameSize;
492 counters_in_use_ = 0;
493}
494
495
496Counter* CounterCollection::GetNextCounter() {
497 if (counters_in_use_ == kMaxCounters) return NULL;
498 return &counters_[counters_in_use_++];
499}
500
501
502void Shell::MapCounters(const char* name) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000503 counters_file_ = i::OS::MemoryMappedFile::create(
504 name, sizeof(CounterCollection), &local_counters_);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000505 void* memory = (counters_file_ == NULL) ?
506 NULL : counters_file_->memory();
507 if (memory == NULL) {
508 printf("Could not map counters file %s\n", name);
509 exit(1);
510 }
511 counters_ = static_cast<CounterCollection*>(memory);
512 V8::SetCounterFunction(LookupCounter);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000513 V8::SetCreateHistogramFunction(CreateHistogram);
514 V8::SetAddHistogramSampleFunction(AddHistogramSample);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000515}
516
517
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000518int CounterMap::Hash(const char* name) {
519 int h = 0;
520 int c;
521 while ((c = *name++) != 0) {
522 h += h << 5;
523 h += c;
524 }
525 return h;
526}
527
528
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000529Counter* Shell::GetCounter(const char* name, bool is_histogram) {
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000530 Counter* counter = counter_map_->Lookup(name);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000531
532 if (counter == NULL) {
533 counter = counters_->GetNextCounter();
534 if (counter != NULL) {
535 counter_map_->Set(name, counter);
536 counter->Bind(name, is_histogram);
537 }
538 } else {
539 ASSERT(counter->is_histogram() == is_histogram);
540 }
541 return counter;
542}
543
544
545int* Shell::LookupCounter(const char* name) {
546 Counter* counter = GetCounter(name, false);
547
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000548 if (counter != NULL) {
549 return counter->ptr();
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000550 } else {
551 return NULL;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000552 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000553}
554
555
556void* Shell::CreateHistogram(const char* name,
557 int min,
558 int max,
559 size_t buckets) {
560 return GetCounter(name, true);
561}
562
563
564void Shell::AddHistogramSample(void* histogram, int sample) {
565 Counter* counter = reinterpret_cast<Counter*>(histogram);
566 counter->AddSample(sample);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000567}
568
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000569
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000570void Shell::InstallUtilityScript() {
571 Locker lock;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000572 HandleScope scope;
ager@chromium.org04921a82011-06-27 13:21:41 +0000573 // If we use the utility context, we have to set the security tokens so that
574 // utility, evaluation and debug context can all access each other.
575 utility_context_->SetSecurityToken(Undefined());
576 evaluation_context_->SetSecurityToken(Undefined());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000577 Context::Scope utility_scope(utility_context_);
ager@chromium.org04921a82011-06-27 13:21:41 +0000578
579#ifdef ENABLE_DEBUGGER_SUPPORT
580 // Install the debugger object in the utility scope
581 i::Debug* debug = i::Isolate::Current()->debug();
582 debug->Load();
583 i::Handle<i::JSObject> js_debug
584 = i::Handle<i::JSObject>(debug->debug_context()->global());
585 utility_context_->Global()->Set(String::New("$debug"),
586 Utils::ToLocal(js_debug));
587 debug->debug_context()->set_security_token(HEAP->undefined_value());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000588#endif // ENABLE_DEBUGGER_SUPPORT
ager@chromium.org04921a82011-06-27 13:21:41 +0000589
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000590 // Run the d8 shell utility script in the utility context
591 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
592 i::Vector<const char> shell_source =
593 i::NativesCollection<i::D8>::GetRawScriptSource(source_index);
594 i::Vector<const char> shell_source_name =
595 i::NativesCollection<i::D8>::GetScriptName(source_index);
596 Handle<String> source = String::New(shell_source.start(),
597 shell_source.length());
598 Handle<String> name = String::New(shell_source_name.start(),
599 shell_source_name.length());
600 Handle<Script> script = Script::Compile(source, name);
601 script->Run();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000602 // Mark the d8 shell script as native to avoid it showing up as normal source
603 // in the debugger.
604 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
605 i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000606 ? i::Handle<i::Script>(i::Script::cast(
607 i::JSFunction::cast(*compiled_script)->shared()->script()))
608 : i::Handle<i::Script>(i::Script::cast(
609 i::SharedFunctionInfo::cast(*compiled_script)->script()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000610 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000611
612#ifdef ENABLE_DEBUGGER_SUPPORT
613 // Start the in-process debugger if requested.
614 if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
615 v8::Debug::SetDebugEventListener(HandleDebugEvent);
616 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000617#endif // ENABLE_DEBUGGER_SUPPORT
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000618}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000619#endif // V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000620
ager@chromium.org04921a82011-06-27 13:21:41 +0000621
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000622#ifdef COMPRESS_STARTUP_DATA_BZ2
623class BZip2Decompressor : public v8::StartupDataDecompressor {
624 public:
625 virtual ~BZip2Decompressor() { }
626
627 protected:
628 virtual int DecompressData(char* raw_data,
629 int* raw_data_size,
630 const char* compressed_data,
631 int compressed_data_size) {
632 ASSERT_EQ(v8::StartupData::kBZip2,
633 v8::V8::GetCompressedStartupDataAlgorithm());
634 unsigned int decompressed_size = *raw_data_size;
635 int result =
636 BZ2_bzBuffToBuffDecompress(raw_data,
637 &decompressed_size,
638 const_cast<char*>(compressed_data),
639 compressed_data_size,
640 0, 1);
641 if (result == BZ_OK) {
642 *raw_data_size = decompressed_size;
643 }
644 return result;
645 }
646};
647#endif
648
649Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000650 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
651 global_template->Set(String::New("print"), FunctionTemplate::New(Print));
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000652 global_template->Set(String::New("write"), FunctionTemplate::New(Write));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000653 global_template->Set(String::New("read"), FunctionTemplate::New(Read));
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000654 global_template->Set(String::New("readline"),
655 FunctionTemplate::New(ReadLine));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000656 global_template->Set(String::New("load"), FunctionTemplate::New(Load));
657 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
658 global_template->Set(String::New("version"), FunctionTemplate::New(Version));
ager@chromium.org71daaf62009-04-01 07:22:49 +0000659
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000660 // Bind the handlers for external arrays.
661 global_template->Set(String::New("Int8Array"),
662 FunctionTemplate::New(Int8Array));
663 global_template->Set(String::New("Uint8Array"),
664 FunctionTemplate::New(Uint8Array));
665 global_template->Set(String::New("Int16Array"),
666 FunctionTemplate::New(Int16Array));
667 global_template->Set(String::New("Uint16Array"),
668 FunctionTemplate::New(Uint16Array));
669 global_template->Set(String::New("Int32Array"),
670 FunctionTemplate::New(Int32Array));
671 global_template->Set(String::New("Uint32Array"),
672 FunctionTemplate::New(Uint32Array));
673 global_template->Set(String::New("Float32Array"),
674 FunctionTemplate::New(Float32Array));
675 global_template->Set(String::New("Float64Array"),
676 FunctionTemplate::New(Float64Array));
677 global_template->Set(String::New("PixelArray"),
678 FunctionTemplate::New(PixelArray));
679
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000680#ifdef LIVE_OBJECT_LIST
681 global_template->Set(String::New("lol_is_enabled"), Boolean::New(true));
682#else
683 global_template->Set(String::New("lol_is_enabled"), Boolean::New(false));
684#endif
685
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000686#ifndef V8_SHARED
ager@chromium.org71daaf62009-04-01 07:22:49 +0000687 Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
688 AddOSMethods(os_templ);
689 global_template->Set(String::New("os"), os_templ);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000690#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000691
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000692 return global_template;
693}
694
ager@chromium.org04921a82011-06-27 13:21:41 +0000695
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000696void Shell::Initialize() {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000697#ifdef COMPRESS_STARTUP_DATA_BZ2
698 BZip2Decompressor startup_data_decompressor;
699 int bz2_result = startup_data_decompressor.Decompress();
700 if (bz2_result != BZ_OK) {
701 fprintf(stderr, "bzip error code: %d\n", bz2_result);
702 exit(1);
703 }
704#endif
705
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000706#ifndef V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000707 Shell::counter_map_ = new CounterMap();
708 // Set up counters
709 if (i::StrLength(i::FLAG_map_counters) != 0)
710 MapCounters(i::FLAG_map_counters);
711 if (i::FLAG_dump_counters) {
712 V8::SetCounterFunction(LookupCounter);
713 V8::SetCreateHistogramFunction(CreateHistogram);
714 V8::SetAddHistogramSampleFunction(AddHistogramSample);
715 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000716#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000717 if (options.test_shell) return;
ager@chromium.org04921a82011-06-27 13:21:41 +0000718
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000719#ifndef V8_SHARED
ager@chromium.org04921a82011-06-27 13:21:41 +0000720 Locker lock;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000721 HandleScope scope;
722 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000723 utility_context_ = Context::New(NULL, global_template);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000724
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000725#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org04921a82011-06-27 13:21:41 +0000726 // Start the debugger agent if requested.
727 if (i::FLAG_debugger_agent) {
728 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
729 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000730#endif // ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000731#endif // V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000732}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000733
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000734
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000735Persistent<Context> Shell::CreateEvaluationContext() {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000736#ifndef V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000737 // This needs to be a critical section since this is not thread-safe
738 i::ScopedLock lock(context_mutex_);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000739#endif // V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000740 // Initialize the global objects
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000741 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000742 Persistent<Context> context = Context::New(NULL, global_template);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +0000743 ASSERT(!context.IsEmpty());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000744 Context::Scope scope(context);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000745
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000746#ifndef V8_SHARED
whesse@chromium.org7b260152011-06-20 15:33:18 +0000747 i::JSArguments js_args = i::FLAG_js_arguments;
748 i::Handle<i::FixedArray> arguments_array =
749 FACTORY->NewFixedArray(js_args.argc());
750 for (int j = 0; j < js_args.argc(); j++) {
751 i::Handle<i::String> arg =
752 FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
753 arguments_array->set(j, *arg);
754 }
755 i::Handle<i::JSArray> arguments_jsarray =
756 FACTORY->NewJSArrayWithElements(arguments_array);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000757 context->Global()->Set(String::New("arguments"),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000758 Utils::ToLocal(arguments_jsarray));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000759#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000760 return context;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000761}
762
763
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000764#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000765void Shell::OnExit() {
766 if (i::FLAG_dump_counters) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000767 printf("+----------------------------------------+-------------+\n");
768 printf("| Name | Value |\n");
769 printf("+----------------------------------------+-------------+\n");
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000770 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
771 Counter* counter = i.CurrentValue();
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000772 if (counter->is_histogram()) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000773 printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
774 printf("| t:%-36s | %11i |\n", i.CurrentKey(), counter->sample_total());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000775 } else {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000776 printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000777 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000778 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000779 printf("+----------------------------------------+-------------+\n");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000780 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000781 if (counters_file_ != NULL)
782 delete counters_file_;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000783}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000784#endif // V8_SHARED
785
786
787static FILE* FOpen(const char* path, const char* mode) {
788#if (defined(_WIN32) || defined(_WIN64))
789 FILE* result;
790 if (fopen_s(&result, path, mode) == 0) {
791 return result;
792 } else {
793 return NULL;
794 }
795#else
796 FILE* file = fopen(path, mode);
797 if (file == NULL) return NULL;
798 struct stat file_stat;
799 if (fstat(fileno(file), &file_stat) != 0) return NULL;
800 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
801 if (is_regular_file) return file;
802 fclose(file);
803 return NULL;
804#endif
805}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000806
807
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +0000808static char* ReadChars(const char* name, int* size_out) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000809 // Release the V8 lock while reading files.
810 v8::Unlocker unlocker(Isolate::GetCurrent());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000811 FILE* file = FOpen(name, "rb");
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000812 if (file == NULL) return NULL;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000813
814 fseek(file, 0, SEEK_END);
815 int size = ftell(file);
816 rewind(file);
817
818 char* chars = new char[size + 1];
819 chars[size] = '\0';
820 for (int i = 0; i < size;) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000821 int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000822 i += read;
823 }
824 fclose(file);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000825 *size_out = size;
826 return chars;
827}
828
829
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000830#ifndef V8_SHARED
ager@chromium.org381abbb2009-02-25 13:23:22 +0000831static char* ReadToken(char* data, char token) {
832 char* next = i::OS::StrChr(data, token);
833 if (next != NULL) {
834 *next = '\0';
835 return (next + 1);
836 }
837
838 return NULL;
839}
840
841
842static char* ReadLine(char* data) {
843 return ReadToken(data, '\n');
844}
845
846
847static char* ReadWord(char* data) {
848 return ReadToken(data, ' ');
849}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000850#endif // V8_SHARED
ager@chromium.org381abbb2009-02-25 13:23:22 +0000851
852
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000853// Reads a file into a v8 string.
854Handle<String> Shell::ReadFile(const char* name) {
855 int size = 0;
856 char* chars = ReadChars(name, &size);
857 if (chars == NULL) return Handle<String>();
858 Handle<String> result = String::New(chars);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000859 delete[] chars;
860 return result;
861}
862
863
864void Shell::RunShell() {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000865 Locker locker;
866 Context::Scope context_scope(evaluation_context_);
867 HandleScope handle_scope;
868 Handle<String> name = String::New("(d8)");
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000869#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000870 LineEditor* editor = LineEditor::Get();
871 printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000872 if (i::FLAG_debugger) {
873 printf("JavaScript debugger enabled\n");
874 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000875 editor->Open();
876 while (true) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000877 i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000878 if (input.is_empty()) break;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000879 editor->AddHistory(*input);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000880 ExecuteString(String::New(*input), name, true, true);
881 }
882 editor->Close();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000883#else
884 printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion());
885 static const int kBufferSize = 256;
886 while (true) {
887 char buffer[kBufferSize];
888 printf("%s", Shell::kPrompt);
889 if (fgets(buffer, kBufferSize, stdin) == NULL) break;
890 ExecuteString(String::New(buffer), name, true, true);
891 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000892#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000893 printf("\n");
894}
895
896
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000897#ifndef V8_SHARED
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000898class ShellThread : public i::Thread {
899 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000900 ShellThread(int no, i::Vector<const char> files)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000901 : Thread("d8:ShellThread"),
902 no_(no), files_(files) { }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000903 virtual void Run();
904 private:
905 int no_;
906 i::Vector<const char> files_;
907};
908
909
910void ShellThread::Run() {
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000911 char* ptr = const_cast<char*>(files_.start());
912 while ((ptr != NULL) && (*ptr != '\0')) {
913 // For each newline-separated line.
ager@chromium.org381abbb2009-02-25 13:23:22 +0000914 char* next_line = ReadLine(ptr);
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000915
ager@chromium.org381abbb2009-02-25 13:23:22 +0000916 if (*ptr == '#') {
917 // Skip comment lines.
918 ptr = next_line;
919 continue;
920 }
921
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000922 // Prepare the context for this thread.
923 Locker locker;
924 HandleScope scope;
925 Persistent<Context> thread_context = Shell::CreateEvaluationContext();
ager@chromium.org381abbb2009-02-25 13:23:22 +0000926 Context::Scope context_scope(thread_context);
927
928 while ((ptr != NULL) && (*ptr != '\0')) {
929 char* filename = ptr;
930 ptr = ReadWord(ptr);
931
932 // Skip empty strings.
933 if (strlen(filename) == 0) {
934 break;
935 }
936
937 Handle<String> str = Shell::ReadFile(filename);
938 if (str.IsEmpty()) {
939 printf("WARNING: %s not found\n", filename);
940 break;
941 }
942
943 Shell::ExecuteString(str, String::New(filename), false, false);
944 }
945
946 thread_context.Dispose();
947 ptr = next_line;
948 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000949}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000950#endif // V8_SHARED
ager@chromium.orgddb913d2009-01-27 10:01:48 +0000951
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000952
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000953void SourceGroup::ExitShell(int exit_code) {
954 // Use _exit instead of exit to avoid races between isolate
955 // threads and static destructors.
956 fflush(stdout);
957 fflush(stderr);
958 _exit(exit_code);
959}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000960
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000961
962void SourceGroup::Execute() {
963 for (int i = begin_offset_; i < end_offset_; ++i) {
964 const char* arg = argv_[i];
965 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
966 // Execute argument given to -e option directly.
967 HandleScope handle_scope;
968 Handle<String> file_name = String::New("unnamed");
969 Handle<String> source = String::New(argv_[i + 1]);
970 if (!Shell::ExecuteString(source, file_name, false, true)) {
971 ExitShell(1);
972 return;
973 }
974 ++i;
975 } else if (arg[0] == '-') {
976 // Ignore other options. They have been parsed already.
977 } else {
978 // Use all other arguments as names of files to load and run.
979 HandleScope handle_scope;
980 Handle<String> file_name = String::New(arg);
981 Handle<String> source = ReadFile(arg);
982 if (source.IsEmpty()) {
983 printf("Error reading '%s'\n", arg);
984 ExitShell(1);
985 return;
986 }
987 if (!Shell::ExecuteString(source, file_name, false, true)) {
988 ExitShell(1);
989 return;
990 }
991 }
992 }
993}
994
995
996Handle<String> SourceGroup::ReadFile(const char* name) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000997 int size;
998 const char* chars = ReadChars(name, &size);
999 if (chars == NULL) return Handle<String>();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001000 Handle<String> result = String::New(chars, size);
1001 delete[] chars;
1002 return result;
1003}
1004
1005
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001006#ifndef V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001007i::Thread::Options SourceGroup::GetThreadOptions() {
1008 i::Thread::Options options;
1009 options.name = "IsolateThread";
1010 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1011 // which is not enough to parse the big literal expressions used in tests.
1012 // The stack size should be at least StackGuard::kLimitSize + some
1013 // OS-specific padding for thread startup code.
1014 options.stack_size = 2 << 20; // 2 Mb seems to be enough
1015 return options;
1016}
1017
1018
1019void SourceGroup::ExecuteInThread() {
1020 Isolate* isolate = Isolate::New();
1021 do {
1022 if (next_semaphore_ != NULL) next_semaphore_->Wait();
1023 {
1024 Isolate::Scope iscope(isolate);
1025 Locker lock(isolate);
1026 HandleScope scope;
1027 Persistent<Context> context = Shell::CreateEvaluationContext();
1028 {
1029 Context::Scope cscope(context);
1030 Execute();
1031 }
1032 context.Dispose();
1033 }
1034 if (done_semaphore_ != NULL) done_semaphore_->Signal();
1035 } while (!Shell::options.last_run);
1036 isolate->Dispose();
1037}
1038
1039
1040void SourceGroup::StartExecuteInThread() {
1041 if (thread_ == NULL) {
1042 thread_ = new IsolateThread(this);
1043 thread_->Start();
1044 }
1045 next_semaphore_->Signal();
1046}
1047
1048
1049void SourceGroup::WaitForThread() {
1050 if (thread_ == NULL) return;
1051 if (Shell::options.last_run) {
1052 thread_->Join();
1053 thread_ = NULL;
1054 } else {
1055 done_semaphore_->Wait();
1056 }
1057}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001058#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001059
1060
1061bool Shell::SetOptions(int argc, char* argv[]) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001062 for (int i = 0; i < argc; i++) {
1063 if (strcmp(argv[i], "--stress-opt") == 0) {
1064 options.stress_opt = true;
1065 argv[i] = NULL;
1066 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1067 options.stress_deopt = true;
1068 argv[i] = NULL;
1069 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1070 // No support for stressing if we can't use --always-opt.
1071 options.stress_opt = false;
1072 options.stress_deopt = false;
1073 } else if (strcmp(argv[i], "--shell") == 0) {
1074 options.interactive_shell = true;
1075 argv[i] = NULL;
1076 } else if (strcmp(argv[i], "--test") == 0) {
1077 options.test_shell = true;
1078 argv[i] = NULL;
1079 } else if (strcmp(argv[i], "--preemption") == 0) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001080#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001081 printf("D8 with shared library does not support multi-threading\n");
1082 return false;
1083#else
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001084 options.use_preemption = true;
1085 argv[i] = NULL;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001086#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001087 } else if (strcmp(argv[i], "--no-preemption") == 0) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001088#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001089 printf("D8 with shared library does not support multi-threading\n");
1090 return false;
1091#else
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001092 options.use_preemption = false;
1093 argv[i] = NULL;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001094#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001095 } else if (strcmp(argv[i], "--preemption-interval") == 0) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001096#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001097 printf("D8 with shared library does not support multi-threading\n");
1098 return false;
1099#else
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001100 if (++i < argc) {
1101 argv[i-1] = NULL;
1102 char* end = NULL;
1103 options.preemption_interval = strtol(argv[i], &end, 10); // NOLINT
1104 if (options.preemption_interval <= 0
1105 || *end != '\0'
1106 || errno == ERANGE) {
1107 printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
1108 return false;
1109 }
1110 argv[i] = NULL;
1111 } else {
1112 printf("Missing value for --preemption-interval\n");
1113 return false;
1114 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001115#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001116 } else if (strcmp(argv[i], "-f") == 0) {
1117 // Ignore any -f flags for compatibility with other stand-alone
1118 // JavaScript engines.
1119 continue;
1120 } else if (strcmp(argv[i], "--isolate") == 0) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001121#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001122 printf("D8 with shared library does not support multi-threading\n");
1123 return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001124#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001125 options.num_isolates++;
1126 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001127#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001128 else if (strcmp(argv[i], "--dump-counters") == 0) {
1129 printf("D8 with shared library does not include counters\n");
1130 return false;
1131 } else if (strcmp(argv[i], "-p") == 0) {
1132 printf("D8 with shared library does not support multi-threading\n");
1133 return false;
1134 } else if (strcmp(argv[i], "--debugger") == 0) {
1135 printf("Javascript debugger not included\n");
1136 return false;
1137 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001138#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001139 }
1140
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001141#ifndef V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001142 // Run parallel threads if we are not using --isolate
1143 for (int i = 1; i < argc; i++) {
1144 if (argv[i] == NULL) continue;
1145 if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
1146 if (options.num_isolates > 1) {
1147 printf("-p is not compatible with --isolate\n");
1148 return false;
1149 }
1150 argv[i] = NULL;
1151 if (options.parallel_files == NULL) {
1152 options.parallel_files = new i::List<i::Vector<const char> >();
1153 }
1154 int size = 0;
1155 const char* files = ReadChars(argv[++i], &size);
1156 if (files == NULL) {
1157 printf("-p option incomplete\n");
1158 return false;
1159 }
1160 argv[i] = NULL;
1161 options.parallel_files->Add(i::Vector<const char>(files, size));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001162 delete[] files;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001163 }
1164 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001165#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001166
1167 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1168
1169 // set up isolated source groups
1170 options.isolate_sources = new SourceGroup[options.num_isolates];
1171 SourceGroup* current = options.isolate_sources;
1172 current->Begin(argv, 1);
1173 for (int i = 1; i < argc; i++) {
1174 const char* str = argv[i];
1175 if (strcmp(str, "--isolate") == 0) {
1176 current->End(i);
1177 current++;
1178 current->Begin(argv, i + 1);
1179 } else if (strncmp(argv[i], "--", 2) == 0) {
1180 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
1181 }
1182 }
1183 current->End(argc);
1184
1185 return true;
1186}
1187
1188
1189int Shell::RunMain(int argc, char* argv[]) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001190#ifndef V8_SHARED
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001191 i::List<i::Thread*> threads(1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001192 if (options.parallel_files != NULL)
1193 for (int i = 0; i < options.parallel_files->length(); i++) {
1194 i::Vector<const char> files = options.parallel_files->at(i);
1195 ShellThread* thread = new ShellThread(threads.length(), files);
1196 thread->Start();
1197 threads.Add(thread);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001198 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001199
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001200 for (int i = 1; i < options.num_isolates; ++i) {
1201 options.isolate_sources[i].StartExecuteInThread();
1202 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001203#endif // V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001204 { // NOLINT
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001205 Locker lock;
1206 HandleScope scope;
1207 Persistent<Context> context = CreateEvaluationContext();
1208 {
1209 Context::Scope cscope(context);
1210 options.isolate_sources[0].Execute();
1211 }
1212 if (options.last_run) {
1213 // Keep using the same context in the interactive shell
1214 evaluation_context_ = context;
1215 } else {
1216 context.Dispose();
1217 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001218
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001219#ifndef V8_SHARED
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001220 // Start preemption if threads have been created and preemption is enabled.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001221 if (options.parallel_files != NULL
1222 && threads.length() > 0
1223 && options.use_preemption) {
1224 Locker::StartPreemption(options.preemption_interval);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001225 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001226#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001227 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001228
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001229#ifndef V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001230 for (int i = 1; i < options.num_isolates; ++i) {
1231 options.isolate_sources[i].WaitForThread();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001232 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001233
1234 if (options.parallel_files != NULL)
1235 for (int i = 0; i < threads.length(); i++) {
1236 i::Thread* thread = threads[i];
1237 thread->Join();
1238 delete thread;
1239 }
1240
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001241 OnExit();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001242#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001243 return 0;
1244}
1245
1246
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001247int Shell::Main(int argc, char* argv[]) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001248 if (!SetOptions(argc, argv)) return 1;
1249 Initialize();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001250
1251 int result = 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001252 if (options.stress_opt || options.stress_deopt) {
1253 Testing::SetStressRunType(
1254 options.stress_opt ? Testing::kStressTypeOpt
1255 : Testing::kStressTypeDeopt);
1256 int stress_runs = Testing::GetStressRuns();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001257 for (int i = 0; i < stress_runs && result == 0; i++) {
1258 printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001259 Testing::PrepareStressRun(i);
1260 options.last_run = (i == stress_runs - 1);
1261 result = RunMain(argc, argv);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001262 }
1263 printf("======== Full Deoptimization =======\n");
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001264 Testing::DeoptimizeAll();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001265 } else {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001266 result = RunMain(argc, argv);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001267 }
1268
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001269
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001270#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
ager@chromium.org04921a82011-06-27 13:21:41 +00001271 // Run remote debugger if requested, but never on --test
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001272 if (i::FLAG_remote_debugger && !options.test_shell) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001273 InstallUtilityScript();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001274 RunRemoteDebugger(i::FLAG_debugger_port);
1275 return 0;
1276 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001277#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001278
ager@chromium.org04921a82011-06-27 13:21:41 +00001279 // Run interactive shell if explicitly requested or if no script has been
1280 // executed, but never on --test
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001281
1282 if (( options.interactive_shell
1283 || !options.script_executed )
1284 && !options.test_shell ) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001285#ifndef V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001286 InstallUtilityScript();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001287#endif // V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001288 RunShell();
1289 }
1290
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001291 V8::Dispose();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001292
1293 return result;
1294}
1295
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001296} // namespace v8
1297
1298
danno@chromium.org40cb8782011-05-25 07:58:50 +00001299#ifndef GOOGLE3
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001300int main(int argc, char* argv[]) {
1301 return v8::Shell::Main(argc, argv);
1302}
danno@chromium.org40cb8782011-05-25 07:58:50 +00001303#endif