blob: f37e731f389d6ebffdf63f759ea4a51e227c1848 [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).
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000044#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
Steve Block44f0eee2011-05-26 01:26:41 +010045#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() :
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000089#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
Steve Block44f0eee2011-05-26 01:26:41 +010090 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
Ben Murdoch3fb3ca82011-12-02 17:19:32 +000098#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
99 ~SourceGroup() {
100 delete next_semaphore_;
101 delete done_semaphore_;
102 }
103#endif // USING_V8_SHARED
104
Steve Block44f0eee2011-05-26 01:26:41 +0100105 void Begin(char** argv, int offset) {
106 argv_ = const_cast<const char**>(argv);
107 begin_offset_ = offset;
108 }
109
110 void End(int offset) { end_offset_ = offset; }
111
112 void Execute() {
113 for (int i = begin_offset_; i < end_offset_; ++i) {
114 const char* arg = argv_[i];
115 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
116 // Execute argument given to -e option directly.
117 v8::HandleScope handle_scope;
118 v8::Handle<v8::String> file_name = v8::String::New("unnamed");
119 v8::Handle<v8::String> source = v8::String::New(argv_[i + 1]);
120 if (!ExecuteString(source, file_name, false, true)) {
121 ExitShell(1);
122 return;
123 }
124 ++i;
125 } else if (arg[0] == '-') {
126 // Ignore other options. They have been parsed already.
127 } else {
128 // Use all other arguments as names of files to load and run.
129 v8::HandleScope handle_scope;
130 v8::Handle<v8::String> file_name = v8::String::New(arg);
131 v8::Handle<v8::String> source = ReadFile(arg);
132 if (source.IsEmpty()) {
133 printf("Error reading '%s'\n", arg);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100134 continue;
Steve Block44f0eee2011-05-26 01:26:41 +0100135 }
136 if (!ExecuteString(source, file_name, false, true)) {
137 ExitShell(1);
138 return;
139 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000140 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000141 }
142 }
Steve Block44f0eee2011-05-26 01:26:41 +0100143
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000144#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
Steve Block44f0eee2011-05-26 01:26:41 +0100145 void StartExecuteInThread() {
146 if (thread_ == NULL) {
147 thread_ = new IsolateThread(this);
148 thread_->Start();
149 }
150 next_semaphore_->Signal();
151 }
152
153 void WaitForThread() {
154 if (thread_ == NULL) return;
155 if (last_run) {
156 thread_->Join();
157 thread_ = NULL;
158 } else {
159 done_semaphore_->Wait();
160 }
161 }
162#endif // USING_V8_SHARED
163
164 private:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000165#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
Steve Block44f0eee2011-05-26 01:26:41 +0100166 static v8::internal::Thread::Options GetThreadOptions() {
167 v8::internal::Thread::Options options;
168 options.name = "IsolateThread";
169 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
170 // which is not enough to parse the big literal expressions used in tests.
171 // The stack size should be at least StackGuard::kLimitSize + some
172 // OS-specific padding for thread startup code.
173 options.stack_size = 2 << 20; // 2 Mb seems to be enough
174 return options;
175 }
176
177 class IsolateThread : public v8::internal::Thread {
178 public:
179 explicit IsolateThread(SourceGroup* group)
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000180 : v8::internal::Thread(GetThreadOptions()), group_(group) {}
Steve Block44f0eee2011-05-26 01:26:41 +0100181
182 virtual void Run() {
183 group_->ExecuteInThread();
184 }
185
186 private:
187 SourceGroup* group_;
188 };
189
190 void ExecuteInThread() {
191 v8::Isolate* isolate = v8::Isolate::New();
192 do {
193 if (next_semaphore_ != NULL) next_semaphore_->Wait();
194 {
195 v8::Isolate::Scope iscope(isolate);
196 v8::HandleScope scope;
197 v8::Persistent<v8::Context> context = CreateShellContext();
198 {
199 v8::Context::Scope cscope(context);
200 Execute();
201 }
202 context.Dispose();
203 }
204 if (done_semaphore_ != NULL) done_semaphore_->Signal();
205 } while (!last_run);
206 isolate->Dispose();
207 }
208
209 v8::internal::Semaphore* next_semaphore_;
210 v8::internal::Semaphore* done_semaphore_;
211 v8::internal::Thread* thread_;
212#endif // USING_V8_SHARED
213
214 const char** argv_;
215 int begin_offset_;
216 int end_offset_;
217};
218
219
220static SourceGroup* isolate_sources = NULL;
221
222
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000223#ifdef COMPRESS_STARTUP_DATA_BZ2
224class BZip2Decompressor : public v8::StartupDataDecompressor {
225 public:
226 virtual ~BZip2Decompressor() { }
227
228 protected:
229 virtual int DecompressData(char* raw_data,
230 int* raw_data_size,
231 const char* compressed_data,
232 int compressed_data_size) {
233 ASSERT_EQ(v8::StartupData::kBZip2,
234 v8::V8::GetCompressedStartupDataAlgorithm());
235 unsigned int decompressed_size = *raw_data_size;
236 int result =
237 BZ2_bzBuffToBuffDecompress(raw_data,
238 &decompressed_size,
239 const_cast<char*>(compressed_data),
240 compressed_data_size,
241 0, 1);
242 if (result == BZ_OK) {
243 *raw_data_size = decompressed_size;
244 }
245 return result;
246 }
247};
248#endif
249
250
Steve Block44f0eee2011-05-26 01:26:41 +0100251int RunMain(int argc, char* argv[]) {
252 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
253 v8::HandleScope handle_scope;
254 v8::Persistent<v8::Context> context = CreateShellContext();
255 // Enter the newly created execution environment.
256 context->Enter();
257 if (context.IsEmpty()) {
258 printf("Error creating context\n");
259 return 1;
260 }
261
262 bool run_shell = (argc == 1);
263 int num_isolates = 1;
264 for (int i = 1; i < argc; i++) {
265 if (strcmp(argv[i], "--isolate") == 0) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000266#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
Steve Block44f0eee2011-05-26 01:26:41 +0100267 ++num_isolates;
268#else // USING_V8_SHARED
269 printf("Error: --isolate not supported when linked with shared "
270 "library\n");
271 ExitShell(1);
272#endif // USING_V8_SHARED
273 }
274 }
275 if (isolate_sources == NULL) {
276 isolate_sources = new SourceGroup[num_isolates];
277 SourceGroup* current = isolate_sources;
278 current->Begin(argv, 1);
279 for (int i = 1; i < argc; i++) {
280 const char* str = argv[i];
281 if (strcmp(str, "--isolate") == 0) {
282 current->End(i);
283 current++;
284 current->Begin(argv, i + 1);
285 } else if (strcmp(str, "--shell") == 0) {
286 run_shell = true;
287 } else if (strcmp(str, "-f") == 0) {
288 // Ignore any -f flags for compatibility with the other stand-
289 // alone JavaScript engines.
290 continue;
291 } else if (strncmp(str, "--", 2) == 0) {
292 printf("Warning: unknown flag %s.\nTry --help for options\n", str);
293 }
294 }
295 current->End(argc);
296 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000297#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
Steve Block44f0eee2011-05-26 01:26:41 +0100298 for (int i = 1; i < num_isolates; ++i) {
299 isolate_sources[i].StartExecuteInThread();
300 }
301#endif // USING_V8_SHARED
302 isolate_sources[0].Execute();
Steve Blocka7e24c12009-10-30 11:49:00 +0000303 if (run_shell) RunShell(context);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000304#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
Steve Block44f0eee2011-05-26 01:26:41 +0100305 for (int i = 1; i < num_isolates; ++i) {
306 isolate_sources[i].WaitForThread();
307 }
308#endif // USING_V8_SHARED
309 if (last_run) {
310 delete[] isolate_sources;
311 isolate_sources = NULL;
312 }
313 context->Exit();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100314 context.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +0000315 return 0;
316}
317
318
319int main(int argc, char* argv[]) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100320 // Figure out if we're requested to stress the optimization
321 // infrastructure by running tests multiple times and forcing
322 // optimization in the last run.
323 bool FLAG_stress_opt = false;
324 bool FLAG_stress_deopt = false;
325 for (int i = 0; i < argc; i++) {
326 if (strcmp(argv[i], "--stress-opt") == 0) {
327 FLAG_stress_opt = true;
328 argv[i] = NULL;
329 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
330 FLAG_stress_deopt = true;
331 argv[i] = NULL;
332 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
333 // No support for stressing if we can't use --always-opt.
334 FLAG_stress_opt = false;
335 FLAG_stress_deopt = false;
336 break;
337 }
338 }
339
Ben Murdoch257744e2011-11-30 15:57:28 +0000340#ifdef COMPRESS_STARTUP_DATA_BZ2
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000341 BZip2Decompressor startup_data_decompressor;
342 int bz2_result = startup_data_decompressor.Decompress();
343 if (bz2_result != BZ_OK) {
344 fprintf(stderr, "bzip error code: %d\n", bz2_result);
345 exit(1);
Ben Murdoch257744e2011-11-30 15:57:28 +0000346 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000347#endif
Ben Murdoch257744e2011-11-30 15:57:28 +0000348
Ben Murdochb0fe1622011-05-05 13:52:32 +0100349 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
350 int result = 0;
351 if (FLAG_stress_opt || FLAG_stress_deopt) {
352 v8::Testing::SetStressRunType(FLAG_stress_opt
353 ? v8::Testing::kStressTypeOpt
354 : v8::Testing::kStressTypeDeopt);
355 int stress_runs = v8::Testing::GetStressRuns();
356 for (int i = 0; i < stress_runs && result == 0; i++) {
357 printf("============ Stress %d/%d ============\n",
358 i + 1, stress_runs);
359 v8::Testing::PrepareStressRun(i);
Steve Block44f0eee2011-05-26 01:26:41 +0100360 last_run = (i == stress_runs - 1);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100361 result = RunMain(argc, argv);
362 }
Steve Block44f0eee2011-05-26 01:26:41 +0100363 printf("======== Full Deoptimization =======\n");
364 v8::Testing::DeoptimizeAll();
Ben Murdochb0fe1622011-05-05 13:52:32 +0100365 } else {
366 result = RunMain(argc, argv);
367 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000368 v8::V8::Dispose();
Ben Murdoch257744e2011-11-30 15:57:28 +0000369
Steve Blocka7e24c12009-10-30 11:49:00 +0000370 return result;
371}
372
373
374// Extracts a C string from a V8 Utf8Value.
375const char* ToCString(const v8::String::Utf8Value& value) {
376 return *value ? *value : "<string conversion failed>";
377}
378
379
Steve Block44f0eee2011-05-26 01:26:41 +0100380// Creates a new execution environment containing the built-in
381// functions.
382v8::Persistent<v8::Context> CreateShellContext() {
383 // Create a template for the global object.
384 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
385 // Bind the global 'print' function to the C++ Print callback.
386 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
387 // Bind the global 'read' function to the C++ Read callback.
388 global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
389 // Bind the global 'load' function to the C++ Load callback.
390 global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
391 // Bind the 'quit' function
392 global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
393 // Bind the 'version' function
394 global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100395
396 // Bind the handlers for external arrays.
397 global->Set(v8::String::New("Int8Array"),
398 v8::FunctionTemplate::New(Int8Array));
399 global->Set(v8::String::New("Uint8Array"),
400 v8::FunctionTemplate::New(Uint8Array));
401 global->Set(v8::String::New("Int16Array"),
402 v8::FunctionTemplate::New(Int16Array));
403 global->Set(v8::String::New("Uint16Array"),
404 v8::FunctionTemplate::New(Uint16Array));
405 global->Set(v8::String::New("Int32Array"),
406 v8::FunctionTemplate::New(Int32Array));
407 global->Set(v8::String::New("Uint32Array"),
408 v8::FunctionTemplate::New(Uint32Array));
409 global->Set(v8::String::New("Float32Array"),
410 v8::FunctionTemplate::New(Float32Array));
Ben Murdoch257744e2011-11-30 15:57:28 +0000411 global->Set(v8::String::New("Float64Array"),
412 v8::FunctionTemplate::New(Float64Array));
Ben Murdoch8b112d22011-06-08 16:22:53 +0100413 global->Set(v8::String::New("PixelArray"),
414 v8::FunctionTemplate::New(PixelArray));
415
Steve Block44f0eee2011-05-26 01:26:41 +0100416 return v8::Context::New(NULL, global);
417}
418
419
Steve Blocka7e24c12009-10-30 11:49:00 +0000420// The callback that is invoked by v8 whenever the JavaScript 'print'
421// function is called. Prints its arguments on stdout separated by
422// spaces and ending with a newline.
423v8::Handle<v8::Value> Print(const v8::Arguments& args) {
424 bool first = true;
425 for (int i = 0; i < args.Length(); i++) {
426 v8::HandleScope handle_scope;
427 if (first) {
428 first = false;
429 } else {
430 printf(" ");
431 }
432 v8::String::Utf8Value str(args[i]);
433 const char* cstr = ToCString(str);
434 printf("%s", cstr);
435 }
436 printf("\n");
437 fflush(stdout);
438 return v8::Undefined();
439}
440
441
442// The callback that is invoked by v8 whenever the JavaScript 'read'
443// function is called. This function loads the content of the file named in
444// the argument into a JavaScript string.
445v8::Handle<v8::Value> Read(const v8::Arguments& args) {
446 if (args.Length() != 1) {
447 return v8::ThrowException(v8::String::New("Bad parameters"));
448 }
449 v8::String::Utf8Value file(args[0]);
450 if (*file == NULL) {
451 return v8::ThrowException(v8::String::New("Error loading file"));
452 }
453 v8::Handle<v8::String> source = ReadFile(*file);
454 if (source.IsEmpty()) {
455 return v8::ThrowException(v8::String::New("Error loading file"));
456 }
457 return source;
458}
459
460
461// The callback that is invoked by v8 whenever the JavaScript 'load'
462// function is called. Loads, compiles and executes its argument
463// JavaScript file.
464v8::Handle<v8::Value> Load(const v8::Arguments& args) {
465 for (int i = 0; i < args.Length(); i++) {
466 v8::HandleScope handle_scope;
467 v8::String::Utf8Value file(args[i]);
468 if (*file == NULL) {
469 return v8::ThrowException(v8::String::New("Error loading file"));
470 }
471 v8::Handle<v8::String> source = ReadFile(*file);
472 if (source.IsEmpty()) {
473 return v8::ThrowException(v8::String::New("Error loading file"));
474 }
475 if (!ExecuteString(source, v8::String::New(*file), false, false)) {
476 return v8::ThrowException(v8::String::New("Error executing file"));
477 }
478 }
479 return v8::Undefined();
480}
481
482
483// The callback that is invoked by v8 whenever the JavaScript 'quit'
484// function is called. Quits.
485v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
486 // If not arguments are given args[0] will yield undefined which
487 // converts to the integer value 0.
488 int exit_code = args[0]->Int32Value();
Steve Block44f0eee2011-05-26 01:26:41 +0100489 ExitShell(exit_code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000490 return v8::Undefined();
491}
492
493
494v8::Handle<v8::Value> Version(const v8::Arguments& args) {
495 return v8::String::New(v8::V8::GetVersion());
496}
497
498
Ben Murdoch8b112d22011-06-08 16:22:53 +0100499void ExternalArrayWeakCallback(v8::Persistent<v8::Value> object, void* data) {
500 free(data);
501 object.Dispose();
502}
503
504
505v8::Handle<v8::Value> CreateExternalArray(const v8::Arguments& args,
506 v8::ExternalArrayType type,
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000507 size_t element_size) {
508 assert(element_size == 1 ||
509 element_size == 2 ||
510 element_size == 4 ||
511 element_size == 8);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100512 if (args.Length() != 1) {
513 return v8::ThrowException(
514 v8::String::New("Array constructor needs one parameter."));
515 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000516 static const int kMaxLength = 0x3fffffff;
517 size_t length = 0;
518 if (args[0]->IsUint32()) {
519 length = args[0]->Uint32Value();
520 } else if (args[0]->IsNumber()) {
521 double raw_length = args[0]->NumberValue();
522 if (raw_length < 0) {
523 return v8::ThrowException(
524 v8::String::New("Array length must not be negative."));
525 }
526 if (raw_length > kMaxLength) {
527 return v8::ThrowException(
528 v8::String::New("Array length exceeds maximum length."));
529 }
530 length = static_cast<size_t>(raw_length);
531 } else {
532 return v8::ThrowException(
533 v8::String::New("Array length must be a number."));
534 }
535 if (length > static_cast<size_t>(kMaxLength)) {
536 return v8::ThrowException(
537 v8::String::New("Array length exceeds maximum length."));
538 }
539 void* data = calloc(length, element_size);
540 if (data == NULL) {
541 return v8::ThrowException(v8::String::New("Memory allocation failed."));
542 }
Ben Murdoch8b112d22011-06-08 16:22:53 +0100543 v8::Handle<v8::Object> array = v8::Object::New();
544 v8::Persistent<v8::Object> persistent_array =
545 v8::Persistent<v8::Object>::New(array);
546 persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
Ben Murdoch257744e2011-11-30 15:57:28 +0000547 persistent_array.MarkIndependent();
Ben Murdoch8b112d22011-06-08 16:22:53 +0100548 array->SetIndexedPropertiesToExternalArrayData(data, type, length);
549 array->Set(v8::String::New("length"), v8::Int32::New(length),
550 v8::ReadOnly);
551 array->Set(v8::String::New("BYTES_PER_ELEMENT"),
552 v8::Int32::New(element_size));
553 return array;
554}
555
556
557v8::Handle<v8::Value> Int8Array(const v8::Arguments& args) {
558 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
559}
560
561
562v8::Handle<v8::Value> Uint8Array(const v8::Arguments& args) {
563 return CreateExternalArray(args, v8::kExternalUnsignedByteArray,
564 sizeof(uint8_t));
565}
566
567
568v8::Handle<v8::Value> Int16Array(const v8::Arguments& args) {
569 return CreateExternalArray(args, v8::kExternalShortArray, sizeof(int16_t));
570}
571
572
573v8::Handle<v8::Value> Uint16Array(const v8::Arguments& args) {
574 return CreateExternalArray(args, v8::kExternalUnsignedShortArray,
575 sizeof(uint16_t));
576}
577
578v8::Handle<v8::Value> Int32Array(const v8::Arguments& args) {
579 return CreateExternalArray(args, v8::kExternalIntArray, sizeof(int32_t));
580}
581
582
583v8::Handle<v8::Value> Uint32Array(const v8::Arguments& args) {
584 return CreateExternalArray(args, v8::kExternalUnsignedIntArray,
585 sizeof(uint32_t));
586}
587
588
589v8::Handle<v8::Value> Float32Array(const v8::Arguments& args) {
590 return CreateExternalArray(args, v8::kExternalFloatArray,
591 sizeof(float)); // NOLINT
592}
593
594
Ben Murdoch257744e2011-11-30 15:57:28 +0000595v8::Handle<v8::Value> Float64Array(const v8::Arguments& args) {
596 return CreateExternalArray(args, v8::kExternalDoubleArray,
597 sizeof(double)); // NOLINT
598}
599
600
Ben Murdoch8b112d22011-06-08 16:22:53 +0100601v8::Handle<v8::Value> PixelArray(const v8::Arguments& args) {
602 return CreateExternalArray(args, v8::kExternalPixelArray, sizeof(uint8_t));
603}
604
605
Steve Blocka7e24c12009-10-30 11:49:00 +0000606// Reads a file into a v8 string.
607v8::Handle<v8::String> ReadFile(const char* name) {
608 FILE* file = fopen(name, "rb");
609 if (file == NULL) return v8::Handle<v8::String>();
610
611 fseek(file, 0, SEEK_END);
612 int size = ftell(file);
613 rewind(file);
614
615 char* chars = new char[size + 1];
616 chars[size] = '\0';
617 for (int i = 0; i < size;) {
618 int read = fread(&chars[i], 1, size - i, file);
619 i += read;
620 }
621 fclose(file);
622 v8::Handle<v8::String> result = v8::String::New(chars, size);
623 delete[] chars;
624 return result;
625}
626
627
628// The read-eval-execute loop of the shell.
629void RunShell(v8::Handle<v8::Context> context) {
630 printf("V8 version %s\n", v8::V8::GetVersion());
631 static const int kBufferSize = 256;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100632 // Enter the execution environment before evaluating any code.
633 v8::Context::Scope context_scope(context);
Steve Blocka7e24c12009-10-30 11:49:00 +0000634 while (true) {
635 char buffer[kBufferSize];
636 printf("> ");
637 char* str = fgets(buffer, kBufferSize, stdin);
638 if (str == NULL) break;
639 v8::HandleScope handle_scope;
640 ExecuteString(v8::String::New(str),
641 v8::String::New("(shell)"),
642 true,
643 true);
644 }
645 printf("\n");
646}
647
648
649// Executes a string within the current v8 context.
650bool ExecuteString(v8::Handle<v8::String> source,
651 v8::Handle<v8::Value> name,
652 bool print_result,
653 bool report_exceptions) {
654 v8::HandleScope handle_scope;
655 v8::TryCatch try_catch;
656 v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
657 if (script.IsEmpty()) {
658 // Print errors that happened during compilation.
659 if (report_exceptions)
660 ReportException(&try_catch);
661 return false;
662 } else {
663 v8::Handle<v8::Value> result = script->Run();
664 if (result.IsEmpty()) {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100665 assert(try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000666 // Print errors that happened during execution.
667 if (report_exceptions)
668 ReportException(&try_catch);
669 return false;
670 } else {
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100671 assert(!try_catch.HasCaught());
Steve Blocka7e24c12009-10-30 11:49:00 +0000672 if (print_result && !result->IsUndefined()) {
673 // If all went well and the result wasn't undefined then print
674 // the returned value.
675 v8::String::Utf8Value str(result);
676 const char* cstr = ToCString(str);
677 printf("%s\n", cstr);
678 }
679 return true;
680 }
681 }
682}
683
684
685void ReportException(v8::TryCatch* try_catch) {
686 v8::HandleScope handle_scope;
687 v8::String::Utf8Value exception(try_catch->Exception());
688 const char* exception_string = ToCString(exception);
689 v8::Handle<v8::Message> message = try_catch->Message();
690 if (message.IsEmpty()) {
691 // V8 didn't provide any extra information about this error; just
692 // print the exception.
693 printf("%s\n", exception_string);
694 } else {
695 // Print (filename):(line number): (message).
696 v8::String::Utf8Value filename(message->GetScriptResourceName());
697 const char* filename_string = ToCString(filename);
698 int linenum = message->GetLineNumber();
699 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
700 // Print line of source code.
701 v8::String::Utf8Value sourceline(message->GetSourceLine());
702 const char* sourceline_string = ToCString(sourceline);
703 printf("%s\n", sourceline_string);
704 // Print wavy underline (GetUnderline is deprecated).
705 int start = message->GetStartColumn();
706 for (int i = 0; i < start; i++) {
707 printf(" ");
708 }
709 int end = message->GetEndColumn();
710 for (int i = start; i < end; i++) {
711 printf("^");
712 }
713 printf("\n");
Kristian Monsen25f61362010-05-21 11:50:48 +0100714 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
715 if (stack_trace.length() > 0) {
716 const char* stack_trace_string = ToCString(stack_trace);
717 printf("%s\n", stack_trace_string);
718 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000719 }
720}