blob: 342031db885bd88439303f118aece568a4995f8d [file] [log] [blame]
Ben Murdoch8b112d22011-06-08 16:22:53 +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#include <v8.h>
Ben Murdochb0fe1622011-05-05 13:52:32 +010029#include <v8-testing.h>
Ben Murdoche0cee9b2011-05-25 10:26:03 +010030#include <assert.h>
Ben Murdoch257744e2011-11-30 15:57:28 +000031#ifdef COMPRESS_STARTUP_DATA_BZ2
32#include <bzlib.h>
33#endif
Steve Blocka7e24c12009-10-30 11:49:00 +000034#include <fcntl.h>
35#include <string.h>
36#include <stdio.h>
37#include <stdlib.h>
38
Steve Block44f0eee2011-05-26 01:26:41 +010039// When building with V8 in a shared library we cannot use functions which
40// is not explicitly a part of the public V8 API. This extensive use of
41// #ifndef USING_V8_SHARED/#endif is a hack until we can resolve whether to
42// still use the shell sample for testing or change to use the developer
43// shell d8 TODO(1272).
44#ifndef USING_V8_SHARED
45#include "../src/v8.h"
46#endif // USING_V8_SHARED
Steve Blocka7e24c12009-10-30 11:49:00 +000047
Steve Block44f0eee2011-05-26 01:26:41 +010048#if !defined(_WIN32) && !defined(_WIN64)
49#include <unistd.h> // NOLINT
50#endif
51
52static void ExitShell(int exit_code) {
53 // Use _exit instead of exit to avoid races between isolate
54 // threads and static destructors.
55 fflush(stdout);
56 fflush(stderr);
57 _exit(exit_code);
58}
59
60v8::Persistent<v8::Context> CreateShellContext();
Steve Blocka7e24c12009-10-30 11:49:00 +000061void RunShell(v8::Handle<v8::Context> context);
62bool ExecuteString(v8::Handle<v8::String> source,
63 v8::Handle<v8::Value> name,
64 bool print_result,
65 bool report_exceptions);
66v8::Handle<v8::Value> Print(const v8::Arguments& args);
67v8::Handle<v8::Value> Read(const v8::Arguments& args);
68v8::Handle<v8::Value> Load(const v8::Arguments& args);
69v8::Handle<v8::Value> Quit(const v8::Arguments& args);
70v8::Handle<v8::Value> Version(const v8::Arguments& args);
Ben Murdoch8b112d22011-06-08 16:22:53 +010071v8::Handle<v8::Value> Int8Array(const v8::Arguments& args);
72v8::Handle<v8::Value> Uint8Array(const v8::Arguments& args);
73v8::Handle<v8::Value> Int16Array(const v8::Arguments& args);
74v8::Handle<v8::Value> Uint16Array(const v8::Arguments& args);
75v8::Handle<v8::Value> Int32Array(const v8::Arguments& args);
76v8::Handle<v8::Value> Uint32Array(const v8::Arguments& args);
77v8::Handle<v8::Value> Float32Array(const v8::Arguments& args);
Ben Murdoch257744e2011-11-30 15:57:28 +000078v8::Handle<v8::Value> Float64Array(const v8::Arguments& args);
Ben Murdoch8b112d22011-06-08 16:22:53 +010079v8::Handle<v8::Value> PixelArray(const v8::Arguments& args);
Steve Blocka7e24c12009-10-30 11:49:00 +000080v8::Handle<v8::String> ReadFile(const char* name);
81void ReportException(v8::TryCatch* handler);
82
83
Steve Block44f0eee2011-05-26 01:26:41 +010084static bool last_run = true;
85
86class SourceGroup {
87 public:
88 SourceGroup() :
89#ifndef USING_V8_SHARED
90 next_semaphore_(v8::internal::OS::CreateSemaphore(0)),
91 done_semaphore_(v8::internal::OS::CreateSemaphore(0)),
92 thread_(NULL),
93#endif // USING_V8_SHARED
94 argv_(NULL),
95 begin_offset_(0),
96 end_offset_(0) { }
97
98 void Begin(char** argv, int offset) {
99 argv_ = const_cast<const char**>(argv);
100 begin_offset_ = offset;
101 }
102
103 void End(int offset) { end_offset_ = offset; }
104
105 void Execute() {
106 for (int i = begin_offset_; i < end_offset_; ++i) {
107 const char* arg = argv_[i];
108 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
109 // Execute argument given to -e option directly.
110 v8::HandleScope handle_scope;
111 v8::Handle<v8::String> file_name = v8::String::New("unnamed");
112 v8::Handle<v8::String> source = v8::String::New(argv_[i + 1]);
113 if (!ExecuteString(source, file_name, false, true)) {
114 ExitShell(1);
115 return;
116 }
117 ++i;
118 } else if (arg[0] == '-') {
119 // Ignore other options. They have been parsed already.
120 } else {
121 // Use all other arguments as names of files to load and run.
122 v8::HandleScope handle_scope;
123 v8::Handle<v8::String> file_name = v8::String::New(arg);
124 v8::Handle<v8::String> source = ReadFile(arg);
125 if (source.IsEmpty()) {
126 printf("Error reading '%s'\n", arg);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100127 continue;
Steve Block44f0eee2011-05-26 01:26:41 +0100128 }
129 if (!ExecuteString(source, file_name, false, true)) {
130 ExitShell(1);
131 return;
132 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000133 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000134 }
135 }
Steve Block44f0eee2011-05-26 01:26:41 +0100136
137#ifndef USING_V8_SHARED
138 void StartExecuteInThread() {
139 if (thread_ == NULL) {
140 thread_ = new IsolateThread(this);
141 thread_->Start();
142 }
143 next_semaphore_->Signal();
144 }
145
146 void WaitForThread() {
147 if (thread_ == NULL) return;
148 if (last_run) {
149 thread_->Join();
150 thread_ = NULL;
151 } else {
152 done_semaphore_->Wait();
153 }
154 }
155#endif // USING_V8_SHARED
156
157 private:
158#ifndef USING_V8_SHARED
159 static v8::internal::Thread::Options GetThreadOptions() {
160 v8::internal::Thread::Options options;
161 options.name = "IsolateThread";
162 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
163 // which is not enough to parse the big literal expressions used in tests.
164 // The stack size should be at least StackGuard::kLimitSize + some
165 // OS-specific padding for thread startup code.
166 options.stack_size = 2 << 20; // 2 Mb seems to be enough
167 return options;
168 }
169
170 class IsolateThread : public v8::internal::Thread {
171 public:
172 explicit IsolateThread(SourceGroup* group)
173 : v8::internal::Thread(NULL, GetThreadOptions()), group_(group) {}
174
175 virtual void Run() {
176 group_->ExecuteInThread();
177 }
178
179 private:
180 SourceGroup* group_;
181 };
182
183 void ExecuteInThread() {
184 v8::Isolate* isolate = v8::Isolate::New();
185 do {
186 if (next_semaphore_ != NULL) next_semaphore_->Wait();
187 {
188 v8::Isolate::Scope iscope(isolate);
189 v8::HandleScope scope;
190 v8::Persistent<v8::Context> context = CreateShellContext();
191 {
192 v8::Context::Scope cscope(context);
193 Execute();
194 }
195 context.Dispose();
196 }
197 if (done_semaphore_ != NULL) done_semaphore_->Signal();
198 } while (!last_run);
199 isolate->Dispose();
200 }
201
202 v8::internal::Semaphore* next_semaphore_;
203 v8::internal::Semaphore* done_semaphore_;
204 v8::internal::Thread* thread_;
205#endif // USING_V8_SHARED
206
207 const char** argv_;
208 int begin_offset_;
209 int end_offset_;
210};
211
212
213static SourceGroup* isolate_sources = NULL;
214
215
216int RunMain(int argc, char* argv[]) {
217 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
218 v8::HandleScope handle_scope;
219 v8::Persistent<v8::Context> context = CreateShellContext();
220 // Enter the newly created execution environment.
221 context->Enter();
222 if (context.IsEmpty()) {
223 printf("Error creating context\n");
224 return 1;
225 }
226
227 bool run_shell = (argc == 1);
228 int num_isolates = 1;
229 for (int i = 1; i < argc; i++) {
230 if (strcmp(argv[i], "--isolate") == 0) {
231#ifndef USING_V8_SHARED
232 ++num_isolates;
233#else // USING_V8_SHARED
234 printf("Error: --isolate not supported when linked with shared "
235 "library\n");
236 ExitShell(1);
237#endif // USING_V8_SHARED
238 }
239 }
240 if (isolate_sources == NULL) {
241 isolate_sources = new SourceGroup[num_isolates];
242 SourceGroup* current = isolate_sources;
243 current->Begin(argv, 1);
244 for (int i = 1; i < argc; i++) {
245 const char* str = argv[i];
246 if (strcmp(str, "--isolate") == 0) {
247 current->End(i);
248 current++;
249 current->Begin(argv, i + 1);
250 } else if (strcmp(str, "--shell") == 0) {
251 run_shell = true;
252 } else if (strcmp(str, "-f") == 0) {
253 // Ignore any -f flags for compatibility with the other stand-
254 // alone JavaScript engines.
255 continue;
256 } else if (strncmp(str, "--", 2) == 0) {
257 printf("Warning: unknown flag %s.\nTry --help for options\n", str);
258 }
259 }
260 current->End(argc);
261 }
262#ifndef USING_V8_SHARED
263 for (int i = 1; i < num_isolates; ++i) {
264 isolate_sources[i].StartExecuteInThread();
265 }
266#endif // USING_V8_SHARED
267 isolate_sources[0].Execute();
Steve Blocka7e24c12009-10-30 11:49:00 +0000268 if (run_shell) RunShell(context);
Steve Block44f0eee2011-05-26 01:26:41 +0100269#ifndef USING_V8_SHARED
270 for (int i = 1; i < num_isolates; ++i) {
271 isolate_sources[i].WaitForThread();
272 }
273#endif // USING_V8_SHARED
274 if (last_run) {
275 delete[] isolate_sources;
276 isolate_sources = NULL;
277 }
278 context->Exit();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100279 context.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +0000280 return 0;
281}
282
283
284int main(int argc, char* argv[]) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100285 // Figure out if we're requested to stress the optimization
286 // infrastructure by running tests multiple times and forcing
287 // optimization in the last run.
288 bool FLAG_stress_opt = false;
289 bool FLAG_stress_deopt = false;
290 for (int i = 0; i < argc; i++) {
291 if (strcmp(argv[i], "--stress-opt") == 0) {
292 FLAG_stress_opt = true;
293 argv[i] = NULL;
294 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
295 FLAG_stress_deopt = true;
296 argv[i] = NULL;
297 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
298 // No support for stressing if we can't use --always-opt.
299 FLAG_stress_opt = false;
300 FLAG_stress_deopt = false;
301 break;
302 }
303 }
304
Ben Murdoch257744e2011-11-30 15:57:28 +0000305#ifdef COMPRESS_STARTUP_DATA_BZ2
306 ASSERT_EQ(v8::StartupData::kBZip2,
307 v8::V8::GetCompressedStartupDataAlgorithm());
308 int compressed_data_count = v8::V8::GetCompressedStartupDataCount();
309 v8::StartupData* compressed_data = new v8::StartupData[compressed_data_count];
310 v8::V8::GetCompressedStartupData(compressed_data);
311 for (int i = 0; i < compressed_data_count; ++i) {
312 char* decompressed = new char[compressed_data[i].raw_size];
313 unsigned int decompressed_size = compressed_data[i].raw_size;
314 int result =
315 BZ2_bzBuffToBuffDecompress(decompressed,
316 &decompressed_size,
317 const_cast<char*>(compressed_data[i].data),
318 compressed_data[i].compressed_size,
319 0, 1);
320 if (result != BZ_OK) {
321 fprintf(stderr, "bzip error code: %d\n", result);
322 exit(1);
323 }
324 compressed_data[i].data = decompressed;
325 compressed_data[i].raw_size = decompressed_size;
326 }
327 v8::V8::SetDecompressedStartupData(compressed_data);
328#endif // COMPRESS_STARTUP_DATA_BZ2
329
Ben Murdochb0fe1622011-05-05 13:52:32 +0100330 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
331 int result = 0;
332 if (FLAG_stress_opt || FLAG_stress_deopt) {
333 v8::Testing::SetStressRunType(FLAG_stress_opt
334 ? v8::Testing::kStressTypeOpt
335 : v8::Testing::kStressTypeDeopt);
336 int stress_runs = v8::Testing::GetStressRuns();
337 for (int i = 0; i < stress_runs && result == 0; i++) {
338 printf("============ Stress %d/%d ============\n",
339 i + 1, stress_runs);
340 v8::Testing::PrepareStressRun(i);
Steve Block44f0eee2011-05-26 01:26:41 +0100341 last_run = (i == stress_runs - 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100342 result = RunMain(argc, argv);
343 }
Steve Block44f0eee2011-05-26 01:26:41 +0100344 printf("======== Full Deoptimization =======\n");
345 v8::Testing::DeoptimizeAll();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100346 } else {
347 result = RunMain(argc, argv);
348 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000349 v8::V8::Dispose();
Ben Murdoch257744e2011-11-30 15:57:28 +0000350
351#ifdef COMPRESS_STARTUP_DATA_BZ2
352 for (int i = 0; i < compressed_data_count; ++i) {
353 delete[] compressed_data[i].data;
354 }
355 delete[] compressed_data;
356#endif // COMPRESS_STARTUP_DATA_BZ2
357
Steve Blocka7e24c12009-10-30 11:49:00 +0000358 return result;
359}
360
361
362// Extracts a C string from a V8 Utf8Value.
363const char* ToCString(const v8::String::Utf8Value& value) {
364 return *value ? *value : "<string conversion failed>";
365}
366
367
Steve Block44f0eee2011-05-26 01:26:41 +0100368// Creates a new execution environment containing the built-in
369// functions.
370v8::Persistent<v8::Context> CreateShellContext() {
371 // Create a template for the global object.
372 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
373 // Bind the global 'print' function to the C++ Print callback.
374 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
375 // Bind the global 'read' function to the C++ Read callback.
376 global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
377 // Bind the global 'load' function to the C++ Load callback.
378 global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
379 // Bind the 'quit' function
380 global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
381 // Bind the 'version' function
382 global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100383
384 // Bind the handlers for external arrays.
385 global->Set(v8::String::New("Int8Array"),
386 v8::FunctionTemplate::New(Int8Array));
387 global->Set(v8::String::New("Uint8Array"),
388 v8::FunctionTemplate::New(Uint8Array));
389 global->Set(v8::String::New("Int16Array"),
390 v8::FunctionTemplate::New(Int16Array));
391 global->Set(v8::String::New("Uint16Array"),
392 v8::FunctionTemplate::New(Uint16Array));
393 global->Set(v8::String::New("Int32Array"),
394 v8::FunctionTemplate::New(Int32Array));
395 global->Set(v8::String::New("Uint32Array"),
396 v8::FunctionTemplate::New(Uint32Array));
397 global->Set(v8::String::New("Float32Array"),
398 v8::FunctionTemplate::New(Float32Array));
Ben Murdoch257744e2011-11-30 15:57:28 +0000399 global->Set(v8::String::New("Float64Array"),
400 v8::FunctionTemplate::New(Float64Array));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100401 global->Set(v8::String::New("PixelArray"),
402 v8::FunctionTemplate::New(PixelArray));
403
Steve Block44f0eee2011-05-26 01:26:41 +0100404 return v8::Context::New(NULL, global);
405}
406
407
Steve Blocka7e24c12009-10-30 11:49:00 +0000408// The callback that is invoked by v8 whenever the JavaScript 'print'
409// function is called. Prints its arguments on stdout separated by
410// spaces and ending with a newline.
411v8::Handle<v8::Value> Print(const v8::Arguments& args) {
412 bool first = true;
413 for (int i = 0; i < args.Length(); i++) {
414 v8::HandleScope handle_scope;
415 if (first) {
416 first = false;
417 } else {
418 printf(" ");
419 }
420 v8::String::Utf8Value str(args[i]);
421 const char* cstr = ToCString(str);
422 printf("%s", cstr);
423 }
424 printf("\n");
425 fflush(stdout);
426 return v8::Undefined();
427}
428
429
430// The callback that is invoked by v8 whenever the JavaScript 'read'
431// function is called. This function loads the content of the file named in
432// the argument into a JavaScript string.
433v8::Handle<v8::Value> Read(const v8::Arguments& args) {
434 if (args.Length() != 1) {
435 return v8::ThrowException(v8::String::New("Bad parameters"));
436 }
437 v8::String::Utf8Value file(args[0]);
438 if (*file == NULL) {
439 return v8::ThrowException(v8::String::New("Error loading file"));
440 }
441 v8::Handle<v8::String> source = ReadFile(*file);
442 if (source.IsEmpty()) {
443 return v8::ThrowException(v8::String::New("Error loading file"));
444 }
445 return source;
446}
447
448
449// The callback that is invoked by v8 whenever the JavaScript 'load'
450// function is called. Loads, compiles and executes its argument
451// JavaScript file.
452v8::Handle<v8::Value> Load(const v8::Arguments& args) {
453 for (int i = 0; i < args.Length(); i++) {
454 v8::HandleScope handle_scope;
455 v8::String::Utf8Value file(args[i]);
456 if (*file == NULL) {
457 return v8::ThrowException(v8::String::New("Error loading file"));
458 }
459 v8::Handle<v8::String> source = ReadFile(*file);
460 if (source.IsEmpty()) {
461 return v8::ThrowException(v8::String::New("Error loading file"));
462 }
463 if (!ExecuteString(source, v8::String::New(*file), false, false)) {
464 return v8::ThrowException(v8::String::New("Error executing file"));
465 }
466 }
467 return v8::Undefined();
468}
469
470
471// The callback that is invoked by v8 whenever the JavaScript 'quit'
472// function is called. Quits.
473v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
474 // If not arguments are given args[0] will yield undefined which
475 // converts to the integer value 0.
476 int exit_code = args[0]->Int32Value();
Steve Block44f0eee2011-05-26 01:26:41 +0100477 ExitShell(exit_code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000478 return v8::Undefined();
479}
480
481
482v8::Handle<v8::Value> Version(const v8::Arguments& args) {
483 return v8::String::New(v8::V8::GetVersion());
484}
485
486
Ben Murdoch8b112d22011-06-08 16:22:53 +0100487void ExternalArrayWeakCallback(v8::Persistent<v8::Value> object, void* data) {
488 free(data);
489 object.Dispose();
490}
491
492
493v8::Handle<v8::Value> CreateExternalArray(const v8::Arguments& args,
494 v8::ExternalArrayType type,
495 int element_size) {
496 if (args.Length() != 1) {
497 return v8::ThrowException(
498 v8::String::New("Array constructor needs one parameter."));
499 }
500 int length = args[0]->Int32Value();
501 void* data = malloc(length * element_size);
502 memset(data, 0, length * element_size);
503 v8::Handle<v8::Object> array = v8::Object::New();
504 v8::Persistent<v8::Object> persistent_array =
505 v8::Persistent<v8::Object>::New(array);
506 persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
Ben Murdoch257744e2011-11-30 15:57:28 +0000507 persistent_array.MarkIndependent();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100508 array->SetIndexedPropertiesToExternalArrayData(data, type, length);
509 array->Set(v8::String::New("length"), v8::Int32::New(length),
510 v8::ReadOnly);
511 array->Set(v8::String::New("BYTES_PER_ELEMENT"),
512 v8::Int32::New(element_size));
513 return array;
514}
515
516
517v8::Handle<v8::Value> Int8Array(const v8::Arguments& args) {
518 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
519}
520
521
522v8::Handle<v8::Value> Uint8Array(const v8::Arguments& args) {
523 return CreateExternalArray(args, v8::kExternalUnsignedByteArray,
524 sizeof(uint8_t));
525}
526
527
528v8::Handle<v8::Value> Int16Array(const v8::Arguments& args) {
529 return CreateExternalArray(args, v8::kExternalShortArray, sizeof(int16_t));
530}
531
532
533v8::Handle<v8::Value> Uint16Array(const v8::Arguments& args) {
534 return CreateExternalArray(args, v8::kExternalUnsignedShortArray,
535 sizeof(uint16_t));
536}
537
538v8::Handle<v8::Value> Int32Array(const v8::Arguments& args) {
539 return CreateExternalArray(args, v8::kExternalIntArray, sizeof(int32_t));
540}
541
542
543v8::Handle<v8::Value> Uint32Array(const v8::Arguments& args) {
544 return CreateExternalArray(args, v8::kExternalUnsignedIntArray,
545 sizeof(uint32_t));
546}
547
548
549v8::Handle<v8::Value> Float32Array(const v8::Arguments& args) {
550 return CreateExternalArray(args, v8::kExternalFloatArray,
551 sizeof(float)); // NOLINT
552}
553
554
Ben Murdoch257744e2011-11-30 15:57:28 +0000555v8::Handle<v8::Value> Float64Array(const v8::Arguments& args) {
556 return CreateExternalArray(args, v8::kExternalDoubleArray,
557 sizeof(double)); // NOLINT
558}
559
560
Ben Murdoch8b112d22011-06-08 16:22:53 +0100561v8::Handle<v8::Value> PixelArray(const v8::Arguments& args) {
562 return CreateExternalArray(args, v8::kExternalPixelArray, sizeof(uint8_t));
563}
564
565
Steve Blocka7e24c12009-10-30 11:49:00 +0000566// Reads a file into a v8 string.
567v8::Handle<v8::String> ReadFile(const char* name) {
568 FILE* file = fopen(name, "rb");
569 if (file == NULL) return v8::Handle<v8::String>();
570
571 fseek(file, 0, SEEK_END);
572 int size = ftell(file);
573 rewind(file);
574
575 char* chars = new char[size + 1];
576 chars[size] = '\0';
577 for (int i = 0; i < size;) {
578 int read = fread(&chars[i], 1, size - i, file);
579 i += read;
580 }
581 fclose(file);
582 v8::Handle<v8::String> result = v8::String::New(chars, size);
583 delete[] chars;
584 return result;
585}
586
587
588// The read-eval-execute loop of the shell.
589void RunShell(v8::Handle<v8::Context> context) {
590 printf("V8 version %s\n", v8::V8::GetVersion());
591 static const int kBufferSize = 256;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100592 // Enter the execution environment before evaluating any code.
593 v8::Context::Scope context_scope(context);
Steve Blocka7e24c12009-10-30 11:49:00 +0000594 while (true) {
595 char buffer[kBufferSize];
596 printf("> ");
597 char* str = fgets(buffer, kBufferSize, stdin);
598 if (str == NULL) break;
599 v8::HandleScope handle_scope;
600 ExecuteString(v8::String::New(str),
601 v8::String::New("(shell)"),
602 true,
603 true);
604 }
605 printf("\n");
606}
607
608
609// Executes a string within the current v8 context.
610bool ExecuteString(v8::Handle<v8::String> source,
611 v8::Handle<v8::Value> name,
612 bool print_result,
613 bool report_exceptions) {
614 v8::HandleScope handle_scope;
615 v8::TryCatch try_catch;
616 v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
617 if (script.IsEmpty()) {
618 // Print errors that happened during compilation.
619 if (report_exceptions)
620 ReportException(&try_catch);
621 return false;
622 } else {
623 v8::Handle<v8::Value> result = script->Run();
624 if (result.IsEmpty()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100625 assert(try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000626 // Print errors that happened during execution.
627 if (report_exceptions)
628 ReportException(&try_catch);
629 return false;
630 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100631 assert(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000632 if (print_result && !result->IsUndefined()) {
633 // If all went well and the result wasn't undefined then print
634 // the returned value.
635 v8::String::Utf8Value str(result);
636 const char* cstr = ToCString(str);
637 printf("%s\n", cstr);
638 }
639 return true;
640 }
641 }
642}
643
644
645void ReportException(v8::TryCatch* try_catch) {
646 v8::HandleScope handle_scope;
647 v8::String::Utf8Value exception(try_catch->Exception());
648 const char* exception_string = ToCString(exception);
649 v8::Handle<v8::Message> message = try_catch->Message();
650 if (message.IsEmpty()) {
651 // V8 didn't provide any extra information about this error; just
652 // print the exception.
653 printf("%s\n", exception_string);
654 } else {
655 // Print (filename):(line number): (message).
656 v8::String::Utf8Value filename(message->GetScriptResourceName());
657 const char* filename_string = ToCString(filename);
658 int linenum = message->GetLineNumber();
659 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
660 // Print line of source code.
661 v8::String::Utf8Value sourceline(message->GetSourceLine());
662 const char* sourceline_string = ToCString(sourceline);
663 printf("%s\n", sourceline_string);
664 // Print wavy underline (GetUnderline is deprecated).
665 int start = message->GetStartColumn();
666 for (int i = 0; i < start; i++) {
667 printf(" ");
668 }
669 int end = message->GetEndColumn();
670 for (int i = start; i < end; i++) {
671 printf("^");
672 }
673 printf("\n");
Kristian Monsen25f61362010-05-21 11:50:48 +0100674 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
675 if (stack_trace.length() > 0) {
676 const char* stack_trace_string = ToCString(stack_trace);
677 printf("%s\n", stack_trace_string);
678 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000679 }
680}