blob: 804b76ceeb5dcdb25030c1c1112de4215223b346 [file] [log] [blame]
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001// Copyright 2012 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
ulan@chromium.orgd6899c32012-05-18 14:12:25 +000029// Defined when linking against shared lib on Windows.
30#if defined(USING_V8_SHARED) && !defined(V8_SHARED)
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000031#define V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000032#endif
33
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000034#ifdef COMPRESS_STARTUP_DATA_BZ2
35#include <bzlib.h>
36#endif
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000037
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000038#include <errno.h>
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000039#include <stdlib.h>
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000040#include <string.h>
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000041#include <sys/stat.h>
ager@chromium.orga74f0da2008-12-03 16:05:52 +000042
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000043#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000044#include <assert.h>
45#include "../include/v8-testing.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000046#endif // V8_SHARED
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000047
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000048#include "d8.h"
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000049
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000050#ifndef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000051#include "api.h"
52#include "checks.h"
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000053#include "d8-debug.h"
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000054#include "debug.h"
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000055#include "natives.h"
ager@chromium.orgddb913d2009-01-27 10:01:48 +000056#include "platform.h"
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000057#include "v8.h"
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000058#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000059
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000060#if !defined(_WIN32) && !defined(_WIN64)
61#include <unistd.h> // NOLINT
62#endif
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000063
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000064#ifndef ASSERT
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000065#define ASSERT(condition) assert(condition)
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000066#endif
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000067
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000068namespace v8 {
69
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000070LineEditor *LineEditor::first_ = NULL;
71
72
73LineEditor::LineEditor(Type type, const char* name)
74 : type_(type),
75 name_(name),
76 next_(first_) {
77 first_ = this;
78}
79
80
81LineEditor* LineEditor::Get() {
82 LineEditor* current = first_;
83 LineEditor* best = current;
84 while (current != NULL) {
85 if (current->type_ > best->type_)
86 best = current;
87 current = current->next_;
88 }
89 return best;
90}
91
92
93class DumbLineEditor: public LineEditor {
94 public:
95 DumbLineEditor() : LineEditor(LineEditor::DUMB, "dumb") { }
ulan@chromium.org2efb9002012-01-19 15:36:35 +000096 virtual Handle<String> Prompt(const char* prompt);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000097};
98
99
100static DumbLineEditor dumb_line_editor;
101
102
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000103Handle<String> DumbLineEditor::Prompt(const char* prompt) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000104 printf("%s", prompt);
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000105 return Shell::ReadFromStdin();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000106}
107
108
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000109#ifndef V8_SHARED
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000110CounterMap* Shell::counter_map_;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000111i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
112CounterCollection Shell::local_counters_;
113CounterCollection* Shell::counters_ = &local_counters_;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000114i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000115Persistent<Context> Shell::utility_context_;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000116#endif // V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000117
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000118LineEditor* Shell::console = NULL;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000119Persistent<Context> Shell::evaluation_context_;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000120ShellOptions Shell::options;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000121const char* Shell::kPrompt = "d8> ";
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000122
123
yangguo@chromium.org659ceec2012-01-26 07:37:54 +0000124const int MB = 1024 * 1024;
125
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) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000147#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000148 bool FLAG_debugger = i::FLAG_debugger;
149#else
150 bool FLAG_debugger = false;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000151#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
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);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000179 size_t count = fwrite(*str, sizeof(**str), str.length(), stdout);
180 (void) count; // Silence GCC-4.5.x "unused result" warning.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000181 printf("\n");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000182 }
183 return true;
184 }
185 }
186}
187
188
189Handle<Value> Shell::Print(const Arguments& args) {
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000190 Handle<Value> val = Write(args);
191 printf("\n");
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000192 fflush(stdout);
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000193 return val;
194}
195
196
197Handle<Value> Shell::Write(const Arguments& args) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000198 for (int i = 0; i < args.Length(); i++) {
199 HandleScope handle_scope;
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +0000200 if (i != 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000201 printf(" ");
202 }
iposva@chromium.org245aa852009-02-10 00:49:54 +0000203 v8::String::Utf8Value str(args[i]);
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000204 int n = static_cast<int>(fwrite(*str, sizeof(**str), str.length(), stdout));
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000205 if (n != str.length()) {
206 printf("Error in fwrite\n");
lrn@chromium.org34e60782011-09-15 07:25:40 +0000207 Exit(1);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000208 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000209 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000210 return Undefined();
211}
212
213
ricow@chromium.org55ee8072011-09-08 16:33:10 +0000214Handle<Value> Shell::EnableProfiler(const Arguments& args) {
215 V8::ResumeProfiler();
216 return Undefined();
217}
218
219
220Handle<Value> Shell::DisableProfiler(const Arguments& args) {
221 V8::PauseProfiler();
222 return Undefined();
223}
224
225
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000226Handle<Value> Shell::Read(const Arguments& args) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000227 String::Utf8Value file(args[0]);
228 if (*file == NULL) {
229 return ThrowException(String::New("Error loading file"));
230 }
231 Handle<String> source = ReadFile(*file);
232 if (source.IsEmpty()) {
233 return ThrowException(String::New("Error loading file"));
234 }
235 return source;
236}
237
238
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000239Handle<String> Shell::ReadFromStdin() {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000240 static const int kBufferSize = 256;
241 char buffer[kBufferSize];
242 Handle<String> accumulator = String::New("");
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000243 int length;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +0000244 while (true) {
245 // Continue reading if the line ends with an escape '\\' or the line has
246 // not been fully read into the buffer yet (does not end with '\n').
247 // If fgets gets an error, just give up.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000248 char* input = NULL;
249 { // Release lock for blocking input.
250 Unlocker unlock(Isolate::GetCurrent());
251 input = fgets(buffer, kBufferSize, stdin);
252 }
253 if (input == NULL) return Handle<String>();
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000254 length = static_cast<int>(strlen(buffer));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +0000255 if (length == 0) {
256 return accumulator;
257 } else if (buffer[length-1] != '\n') {
258 accumulator = String::Concat(accumulator, String::New(buffer, length));
259 } else if (length > 1 && buffer[length-2] == '\\') {
260 buffer[length-2] = '\n';
261 accumulator = String::Concat(accumulator, String::New(buffer, length-1));
262 } else {
263 return String::Concat(accumulator, String::New(buffer, length-1));
264 }
265 }
ager@chromium.orgadd848f2009-08-13 12:44:13 +0000266}
267
268
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000269Handle<Value> Shell::Load(const Arguments& args) {
270 for (int i = 0; i < args.Length(); i++) {
271 HandleScope handle_scope;
272 String::Utf8Value file(args[i]);
iposva@chromium.org245aa852009-02-10 00:49:54 +0000273 if (*file == NULL) {
274 return ThrowException(String::New("Error loading file"));
275 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000276 Handle<String> source = ReadFile(*file);
277 if (source.IsEmpty()) {
278 return ThrowException(String::New("Error loading file"));
279 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000280 if (!ExecuteString(source, String::New(*file), false, true)) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +0000281 return ThrowException(String::New("Error executing file"));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 }
283 }
284 return Undefined();
285}
286
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000287static int32_t convertToInt(Local<Value> value_in, TryCatch* try_catch) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000288 if (value_in->IsInt32()) {
289 return value_in->Int32Value();
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000290 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000291
292 Local<Value> number = value_in->ToNumber();
293 if (try_catch->HasCaught()) return 0;
294
295 ASSERT(number->IsNumber());
296 Local<Int32> int32 = number->ToInt32();
297 if (try_catch->HasCaught() || int32.IsEmpty()) return 0;
298
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000299 int32_t value = int32->Int32Value();
300 if (try_catch->HasCaught()) return 0;
301
302 return value;
303}
304
305
306static int32_t convertToUint(Local<Value> value_in, TryCatch* try_catch) {
307 int32_t raw_value = convertToInt(value_in, try_catch);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000308 if (try_catch->HasCaught()) return 0;
309
310 if (raw_value < 0) {
311 ThrowException(String::New("Array length must not be negative."));
312 return 0;
313 }
314
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000315 static const int kMaxLength = 0x3fffffff;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000316#ifndef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000317 ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000318#endif // V8_SHARED
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000319 if (raw_value > static_cast<int32_t>(kMaxLength)) {
320 ThrowException(
321 String::New("Array length exceeds maximum length."));
322 }
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000323 return raw_value;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000324}
325
326
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000327// TODO(rossberg): should replace these by proper uses of HasInstance,
328// once we figure out a good way to make the templates global.
verwaest@chromium.org37141392012-05-31 13:27:02 +0000329const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_";
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000330const char kArrayMarkerPropName[] = "d8::_is_typed_array_";
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000331
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000332
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000333Handle<Value> Shell::CreateExternalArrayBuffer(Handle<Object> buffer,
334 int32_t length) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000335 static const int32_t kMaxSize = 0x7fffffff;
336 // Make sure the total size fits into a (signed) int.
337 if (length < 0 || length > kMaxSize) {
338 return ThrowException(String::New("ArrayBuffer exceeds maximum size (2G)"));
339 }
340 uint8_t* data = new uint8_t[length];
341 if (data == NULL) {
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000342 return ThrowException(String::New("Memory allocation failed"));
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000343 }
344 memset(data, 0, length);
345
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000346 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True());
347 Persistent<Object> persistent_array = Persistent<Object>::New(buffer);
348 persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
349 persistent_array.MarkIndependent();
350 V8::AdjustAmountOfExternalAllocatedMemory(length);
351
352 buffer->SetIndexedPropertiesToExternalArrayData(
353 data, v8::kExternalByteArray, length);
354 buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly);
355
356 return buffer;
357}
358
359
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000360Handle<Value> Shell::ArrayBuffer(const Arguments& args) {
361 if (!args.IsConstructCall()) {
362 Handle<Value>* rec_args = new Handle<Value>[args.Length()];
363 for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i];
364 Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args);
365 delete[] rec_args;
366 return result;
367 }
368
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000369 if (args.Length() == 0) {
370 return ThrowException(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000371 String::New("ArrayBuffer constructor must have one argument"));
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000372 }
373 TryCatch try_catch;
374 int32_t length = convertToUint(args[0], &try_catch);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000375 if (try_catch.HasCaught()) return try_catch.ReThrow();
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000376
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000377 return CreateExternalArrayBuffer(args.This(), length);
378}
379
380
381Handle<Object> Shell::CreateExternalArray(Handle<Object> array,
382 Handle<Object> buffer,
383 ExternalArrayType type,
384 int32_t length,
385 int32_t byteLength,
386 int32_t byteOffset,
387 int32_t element_size) {
388 ASSERT(element_size == 1 || element_size == 2 ||
389 element_size == 4 || element_size == 8);
390 ASSERT(byteLength == length * element_size);
391
392 void* data = buffer->GetIndexedPropertiesExternalArrayData();
393 ASSERT(data != NULL);
394
395 array->SetIndexedPropertiesToExternalArrayData(
396 static_cast<uint8_t*>(data) + byteOffset, type, length);
397 array->SetHiddenValue(String::New(kArrayMarkerPropName), Int32::New(type));
398 array->Set(String::New("byteLength"), Int32::New(byteLength), ReadOnly);
399 array->Set(String::New("byteOffset"), Int32::New(byteOffset), ReadOnly);
400 array->Set(String::New("length"), Int32::New(length), ReadOnly);
401 array->Set(String::New("BYTES_PER_ELEMENT"), Int32::New(element_size));
402 array->Set(String::New("buffer"), buffer, ReadOnly);
403
404 return array;
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000405}
406
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000407
408Handle<Value> Shell::CreateExternalArray(const Arguments& args,
409 ExternalArrayType type,
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000410 int32_t element_size) {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000411 if (!args.IsConstructCall()) {
412 Handle<Value>* rec_args = new Handle<Value>[args.Length()];
413 for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i];
414 Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args);
415 delete[] rec_args;
416 return result;
417 }
418
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000419 TryCatch try_catch;
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000420 ASSERT(element_size == 1 || element_size == 2 ||
421 element_size == 4 || element_size == 8);
422
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000423 // All of the following constructors are supported:
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000424 // TypedArray(unsigned long length)
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000425 // TypedArray(type[] array)
426 // TypedArray(TypedArray array)
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000427 // TypedArray(ArrayBuffer buffer,
428 // optional unsigned long byteOffset,
429 // optional unsigned long length)
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000430 Handle<Object> buffer;
431 int32_t length;
432 int32_t byteLength;
433 int32_t byteOffset;
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000434 bool init_from_array = false;
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000435 if (args.Length() == 0) {
436 return ThrowException(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000437 String::New("Array constructor must have at least one argument"));
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000438 }
439 if (args[0]->IsObject() &&
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000440 !args[0]->ToObject()->GetHiddenValue(
441 String::New(kArrayBufferMarkerPropName)).IsEmpty()) {
442 // Construct from ArrayBuffer.
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000443 buffer = args[0]->ToObject();
444 int32_t bufferLength =
verwaest@chromium.org37141392012-05-31 13:27:02 +0000445 convertToUint(buffer->Get(String::New("byteLength")), &try_catch);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000446 if (try_catch.HasCaught()) return try_catch.ReThrow();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000447
verwaest@chromium.org37141392012-05-31 13:27:02 +0000448 if (args.Length() < 2 || args[1]->IsUndefined()) {
449 byteOffset = 0;
450 } else {
451 byteOffset = convertToUint(args[1], &try_catch);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000452 if (try_catch.HasCaught()) return try_catch.ReThrow();
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000453 if (byteOffset > bufferLength) {
verwaest@chromium.org37141392012-05-31 13:27:02 +0000454 return ThrowException(String::New("byteOffset out of bounds"));
455 }
456 if (byteOffset % element_size != 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000457 return ThrowException(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000458 String::New("byteOffset must be multiple of element size"));
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000459 }
460 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000461
verwaest@chromium.org37141392012-05-31 13:27:02 +0000462 if (args.Length() < 3 || args[2]->IsUndefined()) {
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000463 byteLength = bufferLength - byteOffset;
464 length = byteLength / element_size;
verwaest@chromium.org37141392012-05-31 13:27:02 +0000465 if (byteLength % element_size != 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000466 return ThrowException(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000467 String::New("buffer size must be multiple of element size"));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000468 }
verwaest@chromium.org37141392012-05-31 13:27:02 +0000469 } else {
470 length = convertToUint(args[2], &try_catch);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000471 if (try_catch.HasCaught()) return try_catch.ReThrow();
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000472 byteLength = length * element_size;
473 if (byteOffset + byteLength > bufferLength) {
474 return ThrowException(String::New("length out of bounds"));
475 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000476 }
verwaest@chromium.org37141392012-05-31 13:27:02 +0000477 } else {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000478 if (args[0]->IsObject() &&
479 args[0]->ToObject()->Has(String::New("length"))) {
480 // Construct from array.
481 length = convertToUint(
482 args[0]->ToObject()->Get(String::New("length")), &try_catch);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000483 if (try_catch.HasCaught()) return try_catch.ReThrow();
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000484 init_from_array = true;
485 } else {
486 // Construct from size.
487 length = convertToUint(args[0], &try_catch);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000488 if (try_catch.HasCaught()) return try_catch.ReThrow();
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000489 }
verwaest@chromium.org37141392012-05-31 13:27:02 +0000490 byteLength = length * element_size;
491 byteOffset = 0;
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000492
493 Handle<Object> global = Context::GetCurrent()->Global();
494 Handle<Value> array_buffer = global->Get(String::New("ArrayBuffer"));
495 ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction());
496 Handle<Value> buffer_args[] = { Uint32::New(byteLength) };
497 Handle<Value> result = Handle<Function>::Cast(array_buffer)->NewInstance(
498 1, buffer_args);
499 if (try_catch.HasCaught()) return result;
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000500 buffer = result->ToObject();
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000501 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000502
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000503 Handle<Object> array = CreateExternalArray(
504 args.This(), buffer, type, length, byteLength, byteOffset, element_size);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000505
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000506 if (init_from_array) {
507 Handle<Object> init = args[0]->ToObject();
508 for (int i = 0; i < length; ++i) array->Set(i, init->Get(i));
509 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000510
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000511 return array;
512}
513
514
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000515Handle<Value> Shell::ArrayBufferSlice(const Arguments& args) {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000516 TryCatch try_catch;
517
518 if (!args.This()->IsObject()) {
519 return ThrowException(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000520 String::New("'slice' invoked on non-object receiver"));
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000521 }
522
523 Local<Object> self = args.This();
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000524 Local<Value> marker =
525 self->GetHiddenValue(String::New(kArrayBufferMarkerPropName));
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000526 if (marker.IsEmpty()) {
527 return ThrowException(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000528 String::New("'slice' invoked on wrong receiver type"));
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000529 }
530
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000531 int32_t length =
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000532 convertToUint(self->Get(String::New("byteLength")), &try_catch);
533 if (try_catch.HasCaught()) return try_catch.ReThrow();
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000534
535 if (args.Length() == 0) {
536 return ThrowException(
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000537 String::New("'slice' must have at least one argument"));
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000538 }
539 int32_t begin = convertToInt(args[0], &try_catch);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000540 if (try_catch.HasCaught()) return try_catch.ReThrow();
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000541 if (begin < 0) begin += length;
542 if (begin < 0) begin = 0;
543 if (begin > length) begin = length;
544
545 int32_t end;
546 if (args.Length() < 2 || args[1]->IsUndefined()) {
547 end = length;
548 } else {
549 end = convertToInt(args[1], &try_catch);
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000550 if (try_catch.HasCaught()) return try_catch.ReThrow();
551 if (end < 0) end += length;
552 if (end < 0) end = 0;
553 if (end > length) end = length;
554 if (end < begin) end = begin;
555 }
556
557 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor());
558 Handle<Value> new_args[] = { Uint32::New(end - begin) };
559 Handle<Value> result = constructor->NewInstance(1, new_args);
560 if (try_catch.HasCaught()) return result;
561 Handle<Object> buffer = result->ToObject();
562 uint8_t* dest =
563 static_cast<uint8_t*>(buffer->GetIndexedPropertiesExternalArrayData());
564 uint8_t* src = begin + static_cast<uint8_t*>(
565 self->GetIndexedPropertiesExternalArrayData());
566 memcpy(dest, src, end - begin);
567
568 return buffer;
569}
570
571
572Handle<Value> Shell::ArraySubArray(const Arguments& args) {
573 TryCatch try_catch;
574
575 if (!args.This()->IsObject()) {
576 return ThrowException(
577 String::New("'subarray' invoked on non-object receiver"));
578 }
579
580 Local<Object> self = args.This();
581 Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName));
582 if (marker.IsEmpty()) {
583 return ThrowException(
584 String::New("'subarray' invoked on wrong receiver type"));
585 }
586
587 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject();
588 if (try_catch.HasCaught()) return try_catch.ReThrow();
589 int32_t length =
590 convertToUint(self->Get(String::New("length")), &try_catch);
591 if (try_catch.HasCaught()) return try_catch.ReThrow();
592 int32_t byteOffset =
593 convertToUint(self->Get(String::New("byteOffset")), &try_catch);
594 if (try_catch.HasCaught()) return try_catch.ReThrow();
595 int32_t element_size =
596 convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch);
597 if (try_catch.HasCaught()) return try_catch.ReThrow();
598
599 if (args.Length() == 0) {
600 return ThrowException(
601 String::New("'subarray' must have at least one argument"));
602 }
603 int32_t begin = convertToInt(args[0], &try_catch);
604 if (try_catch.HasCaught()) return try_catch.ReThrow();
605 if (begin < 0) begin += length;
606 if (begin < 0) begin = 0;
607 if (begin > length) begin = length;
608
609 int32_t end;
610 if (args.Length() < 2 || args[1]->IsUndefined()) {
611 end = length;
612 } else {
613 end = convertToInt(args[1], &try_catch);
614 if (try_catch.HasCaught()) return try_catch.ReThrow();
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000615 if (end < 0) end += length;
616 if (end < 0) end = 0;
617 if (end > length) end = length;
618 if (end < begin) end = begin;
619 }
620
621 length = end - begin;
622 byteOffset += begin * element_size;
623
624 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor());
625 Handle<Value> construct_args[] = {
626 buffer, Uint32::New(byteOffset), Uint32::New(length)
627 };
628 return constructor->NewInstance(3, construct_args);
629}
630
631
svenpanne@chromium.org619781a2012-07-05 08:22:44 +0000632Handle<Value> Shell::ArraySet(const Arguments& args) {
633 TryCatch try_catch;
634
635 if (!args.This()->IsObject()) {
636 return ThrowException(
637 String::New("'set' invoked on non-object receiver"));
638 }
639
640 Local<Object> self = args.This();
641 Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName));
642 if (marker.IsEmpty()) {
643 return ThrowException(
644 String::New("'set' invoked on wrong receiver type"));
645 }
646 int32_t length =
647 convertToUint(self->Get(String::New("length")), &try_catch);
648 if (try_catch.HasCaught()) return try_catch.ReThrow();
649 int32_t element_size =
650 convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch);
651 if (try_catch.HasCaught()) return try_catch.ReThrow();
652
653 if (args.Length() == 0) {
654 return ThrowException(
655 String::New("'set' must have at least one argument"));
656 }
657 if (!args[0]->IsObject() ||
658 !args[0]->ToObject()->Has(String::New("length"))) {
659 return ThrowException(
660 String::New("'set' invoked with non-array argument"));
661 }
662 Handle<Object> source = args[0]->ToObject();
663 int32_t source_length =
664 convertToUint(source->Get(String::New("length")), &try_catch);
665 if (try_catch.HasCaught()) return try_catch.ReThrow();
666
667 int32_t offset;
668 if (args.Length() < 2 || args[1]->IsUndefined()) {
669 offset = 0;
670 } else {
671 offset = convertToUint(args[1], &try_catch);
672 if (try_catch.HasCaught()) return try_catch.ReThrow();
673 }
674 if (offset + source_length > length) {
675 return ThrowException(String::New("offset or source length out of bounds"));
676 }
677
678 int32_t source_element_size;
679 if (source->GetHiddenValue(String::New(kArrayMarkerPropName)).IsEmpty()) {
680 source_element_size = 0;
681 } else {
682 source_element_size =
683 convertToUint(source->Get(String::New("BYTES_PER_ELEMENT")), &try_catch);
684 if (try_catch.HasCaught()) return try_catch.ReThrow();
685 }
686
687 if (element_size == source_element_size &&
688 self->GetConstructor()->StrictEquals(source->GetConstructor())) {
689 // Use memmove on the array buffers.
690 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject();
691 if (try_catch.HasCaught()) return try_catch.ReThrow();
692 Handle<Object> source_buffer =
693 source->Get(String::New("buffer"))->ToObject();
694 if (try_catch.HasCaught()) return try_catch.ReThrow();
695 int32_t byteOffset =
696 convertToUint(self->Get(String::New("byteOffset")), &try_catch);
697 if (try_catch.HasCaught()) return try_catch.ReThrow();
698 int32_t source_byteOffset =
699 convertToUint(source->Get(String::New("byteOffset")), &try_catch);
700 if (try_catch.HasCaught()) return try_catch.ReThrow();
701
702 uint8_t* dest = byteOffset + offset * element_size + static_cast<uint8_t*>(
703 buffer->GetIndexedPropertiesExternalArrayData());
704 uint8_t* src = source_byteOffset + static_cast<uint8_t*>(
705 source_buffer->GetIndexedPropertiesExternalArrayData());
706 memmove(dest, src, source_length * element_size);
707 } else if (source_element_size == 0) {
708 // Source is not a typed array, copy element-wise sequentially.
709 for (int i = 0; i < source_length; ++i) {
710 self->Set(offset + i, source->Get(i));
711 if (try_catch.HasCaught()) return try_catch.ReThrow();
712 }
713 } else {
714 // Need to copy element-wise to make the right conversions.
715 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject();
716 if (try_catch.HasCaught()) return try_catch.ReThrow();
717 Handle<Object> source_buffer =
718 source->Get(String::New("buffer"))->ToObject();
719 if (try_catch.HasCaught()) return try_catch.ReThrow();
720
721 if (buffer->StrictEquals(source_buffer)) {
722 // Same backing store, need to handle overlap correctly.
723 // This gets a bit tricky in the case of different element sizes
724 // (which, of course, is extremely unlikely to ever occur in practice).
725 int32_t byteOffset =
726 convertToUint(self->Get(String::New("byteOffset")), &try_catch);
727 if (try_catch.HasCaught()) return try_catch.ReThrow();
728 int32_t source_byteOffset =
729 convertToUint(source->Get(String::New("byteOffset")), &try_catch);
730 if (try_catch.HasCaught()) return try_catch.ReThrow();
731
732 // Copy as much as we can from left to right.
733 int i = 0;
734 int32_t next_dest_offset = byteOffset + (offset + 1) * element_size;
735 int32_t next_src_offset = source_byteOffset + source_element_size;
736 while (i < length && next_dest_offset <= next_src_offset) {
737 self->Set(offset + i, source->Get(i));
738 ++i;
739 next_dest_offset += element_size;
740 next_src_offset += source_element_size;
741 }
742 // Of what's left, copy as much as we can from right to left.
743 int j = length - 1;
744 int32_t dest_offset = byteOffset + (offset + j) * element_size;
745 int32_t src_offset = source_byteOffset + j * source_element_size;
746 while (j >= i && dest_offset >= src_offset) {
747 self->Set(offset + j, source->Get(j));
748 --j;
749 dest_offset -= element_size;
750 src_offset -= source_element_size;
751 }
752 // There can be at most 8 entries left in the middle that need buffering
753 // (because the largest element_size is 8 times the smallest).
754 ASSERT(j+1 - i <= 8);
755 Handle<Value> temp[8];
756 for (int k = i; k <= j; ++k) {
757 temp[k - i] = source->Get(k);
758 }
759 for (int k = i; k <= j; ++k) {
760 self->Set(offset + k, temp[k - i]);
761 }
762 } else {
763 // Different backing stores, safe to copy element-wise sequentially.
764 for (int i = 0; i < source_length; ++i)
765 self->Set(offset + i, source->Get(i));
766 }
767 }
768
769 return Undefined();
770}
771
772
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000773void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000774 HandleScope scope;
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000775 int32_t length =
776 object->ToObject()->Get(String::New("byteLength"))->Uint32Value();
777 V8::AdjustAmountOfExternalAllocatedMemory(-length);
rossberg@chromium.org400388e2012-06-06 09:29:22 +0000778 delete[] static_cast<uint8_t*>(data);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000779 object.Dispose();
780}
781
782
783Handle<Value> Shell::Int8Array(const Arguments& args) {
784 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
785}
786
787
788Handle<Value> Shell::Uint8Array(const Arguments& args) {
789 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t));
790}
791
792
793Handle<Value> Shell::Int16Array(const Arguments& args) {
794 return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t));
795}
796
797
798Handle<Value> Shell::Uint16Array(const Arguments& args) {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000799 return CreateExternalArray(
800 args, kExternalUnsignedShortArray, sizeof(uint16_t));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000801}
802
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000803
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000804Handle<Value> Shell::Int32Array(const Arguments& args) {
805 return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t));
806}
807
808
809Handle<Value> Shell::Uint32Array(const Arguments& args) {
810 return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t));
811}
812
813
814Handle<Value> Shell::Float32Array(const Arguments& args) {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000815 return CreateExternalArray(
816 args, kExternalFloatArray, sizeof(float)); // NOLINT
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000817}
818
819
820Handle<Value> Shell::Float64Array(const Arguments& args) {
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000821 return CreateExternalArray(
822 args, kExternalDoubleArray, sizeof(double)); // NOLINT
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000823}
824
825
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +0000826Handle<Value> Shell::Uint8ClampedArray(const Arguments& args) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000827 return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t));
828}
829
830
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000831Handle<Value> Shell::Yield(const Arguments& args) {
832 v8::Unlocker unlocker;
833 return Undefined();
834}
835
836
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000837Handle<Value> Shell::Quit(const Arguments& args) {
838 int exit_code = args[0]->Int32Value();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000839#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000840 OnExit();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000841#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000842 exit(exit_code);
843 return Undefined();
844}
845
846
847Handle<Value> Shell::Version(const Arguments& args) {
848 return String::New(V8::GetVersion());
849}
850
851
852void Shell::ReportException(v8::TryCatch* try_catch) {
853 HandleScope handle_scope;
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000854#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
855 bool enter_context = !Context::InContext();
856 if (enter_context) utility_context_->Enter();
857#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
iposva@chromium.org245aa852009-02-10 00:49:54 +0000858 v8::String::Utf8Value exception(try_catch->Exception());
859 const char* exception_string = ToCString(exception);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000860 Handle<Message> message = try_catch->Message();
861 if (message.IsEmpty()) {
862 // V8 didn't provide any extra information about this error; just
863 // print the exception.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000864 printf("%s\n", exception_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000865 } else {
866 // Print (filename):(line number): (message).
iposva@chromium.org245aa852009-02-10 00:49:54 +0000867 v8::String::Utf8Value filename(message->GetScriptResourceName());
868 const char* filename_string = ToCString(filename);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000869 int linenum = message->GetLineNumber();
iposva@chromium.org245aa852009-02-10 00:49:54 +0000870 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000871 // Print line of source code.
iposva@chromium.org245aa852009-02-10 00:49:54 +0000872 v8::String::Utf8Value sourceline(message->GetSourceLine());
873 const char* sourceline_string = ToCString(sourceline);
874 printf("%s\n", sourceline_string);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000875 // Print wavy underline (GetUnderline is deprecated).
876 int start = message->GetStartColumn();
877 for (int i = 0; i < start; i++) {
878 printf(" ");
879 }
880 int end = message->GetEndColumn();
881 for (int i = start; i < end; i++) {
882 printf("^");
883 }
884 printf("\n");
danno@chromium.org40cb8782011-05-25 07:58:50 +0000885 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
886 if (stack_trace.length() > 0) {
887 const char* stack_trace_string = ToCString(stack_trace);
888 printf("%s\n", stack_trace_string);
889 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000890 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000891 printf("\n");
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000892#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
893 if (enter_context) utility_context_->Exit();
894#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000895}
896
897
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000898#ifndef V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000899Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
900 HandleScope handle_scope;
901 Context::Scope context_scope(utility_context_);
902 Handle<Object> global = utility_context_->Global();
903 Handle<Value> fun = global->Get(String::New("GetCompletions"));
904 static const int kArgc = 3;
905 Handle<Value> argv[kArgc] = { evaluation_context_->Global(), text, full };
906 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
907 return handle_scope.Close(Handle<Array>::Cast(val));
908}
909
910
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000911#ifdef ENABLE_DEBUGGER_SUPPORT
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000912Handle<Object> Shell::DebugMessageDetails(Handle<String> message) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000913 Context::Scope context_scope(utility_context_);
914 Handle<Object> global = utility_context_->Global();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000915 Handle<Value> fun = global->Get(String::New("DebugMessageDetails"));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000916 static const int kArgc = 1;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000917 Handle<Value> argv[kArgc] = { message };
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000918 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000919 return Handle<Object>::Cast(val);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000920}
921
922
923Handle<Value> Shell::DebugCommandToJSONRequest(Handle<String> command) {
924 Context::Scope context_scope(utility_context_);
925 Handle<Object> global = utility_context_->Global();
926 Handle<Value> fun = global->Get(String::New("DebugCommandToJSONRequest"));
927 static const int kArgc = 1;
928 Handle<Value> argv[kArgc] = { command };
929 Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
930 return val;
931}
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +0000932
933
934void Shell::DispatchDebugMessages() {
935 v8::Context::Scope scope(Shell::evaluation_context_);
936 v8::Debug::ProcessDebugMessages();
937}
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000938#endif // ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000939#endif // V8_SHARED
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +0000940
941
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000942#ifndef V8_SHARED
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000943int32_t* Counter::Bind(const char* name, bool is_histogram) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000944 int i;
945 for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
946 name_[i] = static_cast<char>(name[i]);
947 name_[i] = '\0';
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000948 is_histogram_ = is_histogram;
949 return ptr();
950}
951
952
953void Counter::AddSample(int32_t sample) {
954 count_++;
955 sample_total_ += sample;
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000956}
957
958
959CounterCollection::CounterCollection() {
960 magic_number_ = 0xDEADFACE;
961 max_counters_ = kMaxCounters;
962 max_name_size_ = Counter::kMaxNameSize;
963 counters_in_use_ = 0;
964}
965
966
967Counter* CounterCollection::GetNextCounter() {
968 if (counters_in_use_ == kMaxCounters) return NULL;
969 return &counters_[counters_in_use_++];
970}
971
972
973void Shell::MapCounters(const char* name) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +0000974 counters_file_ = i::OS::MemoryMappedFile::create(
975 name, sizeof(CounterCollection), &local_counters_);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000976 void* memory = (counters_file_ == NULL) ?
977 NULL : counters_file_->memory();
978 if (memory == NULL) {
979 printf("Could not map counters file %s\n", name);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000980 Exit(1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000981 }
982 counters_ = static_cast<CounterCollection*>(memory);
983 V8::SetCounterFunction(LookupCounter);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +0000984 V8::SetCreateHistogramFunction(CreateHistogram);
985 V8::SetAddHistogramSampleFunction(AddHistogramSample);
ager@chromium.orga74f0da2008-12-03 16:05:52 +0000986}
987
988
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +0000989int CounterMap::Hash(const char* name) {
990 int h = 0;
991 int c;
992 while ((c = *name++) != 0) {
993 h += h << 5;
994 h += c;
995 }
996 return h;
997}
998
999
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001000Counter* Shell::GetCounter(const char* name, bool is_histogram) {
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00001001 Counter* counter = counter_map_->Lookup(name);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001002
1003 if (counter == NULL) {
1004 counter = counters_->GetNextCounter();
1005 if (counter != NULL) {
1006 counter_map_->Set(name, counter);
1007 counter->Bind(name, is_histogram);
1008 }
1009 } else {
1010 ASSERT(counter->is_histogram() == is_histogram);
1011 }
1012 return counter;
1013}
1014
1015
1016int* Shell::LookupCounter(const char* name) {
1017 Counter* counter = GetCounter(name, false);
1018
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00001019 if (counter != NULL) {
1020 return counter->ptr();
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001021 } else {
1022 return NULL;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001023 }
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001024}
1025
1026
1027void* Shell::CreateHistogram(const char* name,
1028 int min,
1029 int max,
1030 size_t buckets) {
1031 return GetCounter(name, true);
1032}
1033
1034
1035void Shell::AddHistogramSample(void* histogram, int sample) {
1036 Counter* counter = reinterpret_cast<Counter*>(histogram);
1037 counter->AddSample(sample);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001038}
1039
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001040
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001041void Shell::InstallUtilityScript() {
1042 Locker lock;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001043 HandleScope scope;
ager@chromium.org04921a82011-06-27 13:21:41 +00001044 // If we use the utility context, we have to set the security tokens so that
1045 // utility, evaluation and debug context can all access each other.
1046 utility_context_->SetSecurityToken(Undefined());
1047 evaluation_context_->SetSecurityToken(Undefined());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001048 Context::Scope utility_scope(utility_context_);
ager@chromium.org04921a82011-06-27 13:21:41 +00001049
1050#ifdef ENABLE_DEBUGGER_SUPPORT
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001051 if (i::FLAG_debugger) printf("JavaScript debugger enabled\n");
ager@chromium.org04921a82011-06-27 13:21:41 +00001052 // Install the debugger object in the utility scope
1053 i::Debug* debug = i::Isolate::Current()->debug();
1054 debug->Load();
1055 i::Handle<i::JSObject> js_debug
1056 = i::Handle<i::JSObject>(debug->debug_context()->global());
1057 utility_context_->Global()->Set(String::New("$debug"),
1058 Utils::ToLocal(js_debug));
1059 debug->debug_context()->set_security_token(HEAP->undefined_value());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001060#endif // ENABLE_DEBUGGER_SUPPORT
ager@chromium.org04921a82011-06-27 13:21:41 +00001061
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001062 // Run the d8 shell utility script in the utility context
1063 int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
1064 i::Vector<const char> shell_source =
1065 i::NativesCollection<i::D8>::GetRawScriptSource(source_index);
1066 i::Vector<const char> shell_source_name =
1067 i::NativesCollection<i::D8>::GetScriptName(source_index);
1068 Handle<String> source = String::New(shell_source.start(),
1069 shell_source.length());
1070 Handle<String> name = String::New(shell_source_name.start(),
1071 shell_source_name.length());
1072 Handle<Script> script = Script::Compile(source, name);
1073 script->Run();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001074 // Mark the d8 shell script as native to avoid it showing up as normal source
1075 // in the debugger.
1076 i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
1077 i::Handle<i::Script> script_object = compiled_script->IsJSFunction()
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001078 ? i::Handle<i::Script>(i::Script::cast(
1079 i::JSFunction::cast(*compiled_script)->shared()->script()))
1080 : i::Handle<i::Script>(i::Script::cast(
1081 i::SharedFunctionInfo::cast(*compiled_script)->script()));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001082 script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001083
1084#ifdef ENABLE_DEBUGGER_SUPPORT
1085 // Start the in-process debugger if requested.
1086 if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
1087 v8::Debug::SetDebugEventListener(HandleDebugEvent);
1088 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001089#endif // ENABLE_DEBUGGER_SUPPORT
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001090}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001091#endif // V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001092
ager@chromium.org04921a82011-06-27 13:21:41 +00001093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001094#ifdef COMPRESS_STARTUP_DATA_BZ2
1095class BZip2Decompressor : public v8::StartupDataDecompressor {
1096 public:
1097 virtual ~BZip2Decompressor() { }
1098
1099 protected:
1100 virtual int DecompressData(char* raw_data,
1101 int* raw_data_size,
1102 const char* compressed_data,
1103 int compressed_data_size) {
1104 ASSERT_EQ(v8::StartupData::kBZip2,
1105 v8::V8::GetCompressedStartupDataAlgorithm());
1106 unsigned int decompressed_size = *raw_data_size;
1107 int result =
1108 BZ2_bzBuffToBuffDecompress(raw_data,
1109 &decompressed_size,
1110 const_cast<char*>(compressed_data),
1111 compressed_data_size,
1112 0, 1);
1113 if (result == BZ_OK) {
1114 *raw_data_size = decompressed_size;
1115 }
1116 return result;
1117 }
1118};
1119#endif
1120
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001121
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00001122Handle<FunctionTemplate> Shell::CreateArrayBufferTemplate(
1123 InvocationCallback fun) {
1124 Handle<FunctionTemplate> buffer_template = FunctionTemplate::New(fun);
1125 Local<Template> proto_template = buffer_template->PrototypeTemplate();
1126 proto_template->Set(String::New("slice"),
1127 FunctionTemplate::New(ArrayBufferSlice));
1128 return buffer_template;
1129}
1130
1131
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001132Handle<FunctionTemplate> Shell::CreateArrayTemplate(InvocationCallback fun) {
1133 Handle<FunctionTemplate> array_template = FunctionTemplate::New(fun);
1134 Local<Template> proto_template = array_template->PrototypeTemplate();
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00001135 proto_template->Set(String::New("set"), FunctionTemplate::New(ArraySet));
1136 proto_template->Set(String::New("subarray"),
1137 FunctionTemplate::New(ArraySubArray));
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001138 return array_template;
1139}
1140
1141
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001142Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001143 Handle<ObjectTemplate> global_template = ObjectTemplate::New();
1144 global_template->Set(String::New("print"), FunctionTemplate::New(Print));
christian.plesner.hansen@gmail.com5a6af922009-08-12 14:20:51 +00001145 global_template->Set(String::New("write"), FunctionTemplate::New(Write));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001146 global_template->Set(String::New("read"), FunctionTemplate::New(Read));
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001147 global_template->Set(String::New("readbuffer"),
1148 FunctionTemplate::New(ReadBuffer));
ager@chromium.orgadd848f2009-08-13 12:44:13 +00001149 global_template->Set(String::New("readline"),
1150 FunctionTemplate::New(ReadLine));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001151 global_template->Set(String::New("load"), FunctionTemplate::New(Load));
1152 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
1153 global_template->Set(String::New("version"), FunctionTemplate::New(Version));
ricow@chromium.org55ee8072011-09-08 16:33:10 +00001154 global_template->Set(String::New("enableProfiler"),
1155 FunctionTemplate::New(EnableProfiler));
1156 global_template->Set(String::New("disableProfiler"),
1157 FunctionTemplate::New(DisableProfiler));
ager@chromium.org71daaf62009-04-01 07:22:49 +00001158
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001159 // Bind the handlers for external arrays.
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001160 PropertyAttribute attr =
1161 static_cast<PropertyAttribute>(ReadOnly | DontDelete);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001162 global_template->Set(String::New("ArrayBuffer"),
svenpanne@chromium.org619781a2012-07-05 08:22:44 +00001163 CreateArrayBufferTemplate(ArrayBuffer), attr);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001164 global_template->Set(String::New("Int8Array"),
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001165 CreateArrayTemplate(Int8Array), attr);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001166 global_template->Set(String::New("Uint8Array"),
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001167 CreateArrayTemplate(Uint8Array), attr);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001168 global_template->Set(String::New("Int16Array"),
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001169 CreateArrayTemplate(Int16Array), attr);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001170 global_template->Set(String::New("Uint16Array"),
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001171 CreateArrayTemplate(Uint16Array), attr);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001172 global_template->Set(String::New("Int32Array"),
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001173 CreateArrayTemplate(Int32Array), attr);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001174 global_template->Set(String::New("Uint32Array"),
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001175 CreateArrayTemplate(Uint32Array), attr);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001176 global_template->Set(String::New("Float32Array"),
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001177 CreateArrayTemplate(Float32Array), attr);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001178 global_template->Set(String::New("Float64Array"),
yangguo@chromium.orgc74d6742012-06-29 15:15:45 +00001179 CreateArrayTemplate(Float64Array), attr);
1180 global_template->Set(String::New("Uint8ClampedArray"),
1181 CreateArrayTemplate(Uint8ClampedArray), attr);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001182
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001183#ifdef LIVE_OBJECT_LIST
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001184 global_template->Set(String::New("lol_is_enabled"), True());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001185#else
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001186 global_template->Set(String::New("lol_is_enabled"), False());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001187#endif
1188
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001189#if !defined(V8_SHARED) && !defined(_WIN32) && !defined(_WIN64)
ager@chromium.org71daaf62009-04-01 07:22:49 +00001190 Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
1191 AddOSMethods(os_templ);
1192 global_template->Set(String::New("os"), os_templ);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001193#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001194
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001195 return global_template;
1196}
1197
ager@chromium.org04921a82011-06-27 13:21:41 +00001198
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001199void Shell::Initialize() {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001200#ifdef COMPRESS_STARTUP_DATA_BZ2
1201 BZip2Decompressor startup_data_decompressor;
1202 int bz2_result = startup_data_decompressor.Decompress();
1203 if (bz2_result != BZ_OK) {
1204 fprintf(stderr, "bzip error code: %d\n", bz2_result);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001205 Exit(1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001206 }
1207#endif
1208
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001209#ifndef V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001210 Shell::counter_map_ = new CounterMap();
1211 // Set up counters
1212 if (i::StrLength(i::FLAG_map_counters) != 0)
1213 MapCounters(i::FLAG_map_counters);
1214 if (i::FLAG_dump_counters) {
1215 V8::SetCounterFunction(LookupCounter);
1216 V8::SetCreateHistogramFunction(CreateHistogram);
1217 V8::SetAddHistogramSampleFunction(AddHistogramSample);
1218 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001219#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001220 if (options.test_shell) return;
ager@chromium.org04921a82011-06-27 13:21:41 +00001221
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001222#ifndef V8_SHARED
ager@chromium.org04921a82011-06-27 13:21:41 +00001223 Locker lock;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001224 HandleScope scope;
1225 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001226 utility_context_ = Context::New(NULL, global_template);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001227
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001228#ifdef ENABLE_DEBUGGER_SUPPORT
ager@chromium.org04921a82011-06-27 13:21:41 +00001229 // Start the debugger agent if requested.
1230 if (i::FLAG_debugger_agent) {
1231 v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001232 v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true);
ager@chromium.org04921a82011-06-27 13:21:41 +00001233 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001234#endif // ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001235#endif // V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001236}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001237
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001238
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001239Persistent<Context> Shell::CreateEvaluationContext() {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001240#ifndef V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001241 // This needs to be a critical section since this is not thread-safe
1242 i::ScopedLock lock(context_mutex_);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001243#endif // V8_SHARED
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001244 // Initialize the global objects
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001245 Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001246 Persistent<Context> context = Context::New(NULL, global_template);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00001247 ASSERT(!context.IsEmpty());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001248 Context::Scope scope(context);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001249
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001250#ifndef V8_SHARED
whesse@chromium.org7b260152011-06-20 15:33:18 +00001251 i::JSArguments js_args = i::FLAG_js_arguments;
1252 i::Handle<i::FixedArray> arguments_array =
1253 FACTORY->NewFixedArray(js_args.argc());
1254 for (int j = 0; j < js_args.argc(); j++) {
1255 i::Handle<i::String> arg =
1256 FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
1257 arguments_array->set(j, *arg);
1258 }
1259 i::Handle<i::JSArray> arguments_jsarray =
1260 FACTORY->NewJSArrayWithElements(arguments_array);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001261 context->Global()->Set(String::New("arguments"),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001262 Utils::ToLocal(arguments_jsarray));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001263#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001264 return context;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001265}
1266
1267
lrn@chromium.org34e60782011-09-15 07:25:40 +00001268void Shell::Exit(int exit_code) {
1269 // Use _exit instead of exit to avoid races between isolate
1270 // threads and static destructors.
1271 fflush(stdout);
1272 fflush(stderr);
1273 _exit(exit_code);
1274}
1275
1276
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001277#ifndef V8_SHARED
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001278struct CounterAndKey {
1279 Counter* counter;
1280 const char* key;
1281};
1282
1283
1284int CompareKeys(const void* a, const void* b) {
1285 return strcmp(static_cast<const CounterAndKey*>(a)->key,
1286 static_cast<const CounterAndKey*>(b)->key);
1287}
1288
1289
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001290void Shell::OnExit() {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001291 if (console != NULL) console->Close();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001292 if (i::FLAG_dump_counters) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001293 int number_of_counters = 0;
kasperl@chromium.orgf5aa8372009-03-24 14:47:14 +00001294 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001295 number_of_counters++;
1296 }
1297 CounterAndKey* counters = new CounterAndKey[number_of_counters];
1298 int j = 0;
1299 for (CounterMap::Iterator i(counter_map_); i.More(); i.Next(), j++) {
1300 counters[j].counter = i.CurrentValue();
1301 counters[j].key = i.CurrentKey();
1302 }
1303 qsort(counters, number_of_counters, sizeof(counters[0]), CompareKeys);
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001304 printf("+----------------------------------------------------------------+"
1305 "-------------+\n");
1306 printf("| Name |"
1307 " Value |\n");
1308 printf("+----------------------------------------------------------------+"
1309 "-------------+\n");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001310 for (j = 0; j < number_of_counters; j++) {
1311 Counter* counter = counters[j].counter;
1312 const char* key = counters[j].key;
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001313 if (counter->is_histogram()) {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001314 printf("| c:%-60s | %11i |\n", key, counter->count());
1315 printf("| t:%-60s | %11i |\n", key, counter->sample_total());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001316 } else {
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001317 printf("| %-62s | %11i |\n", key, counter->count());
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00001318 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001319 }
jkummerow@chromium.org28583c92012-07-16 11:31:55 +00001320 printf("+----------------------------------------------------------------+"
1321 "-------------+\n");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001322 delete [] counters;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001323 }
jkummerow@chromium.org1456e702012-03-30 08:38:13 +00001324 delete counters_file_;
1325 delete counter_map_;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001326}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001327#endif // V8_SHARED
1328
1329
1330static FILE* FOpen(const char* path, const char* mode) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001331#if defined(_MSC_VER) && (defined(_WIN32) || defined(_WIN64))
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001332 FILE* result;
1333 if (fopen_s(&result, path, mode) == 0) {
1334 return result;
1335 } else {
1336 return NULL;
1337 }
1338#else
1339 FILE* file = fopen(path, mode);
1340 if (file == NULL) return NULL;
1341 struct stat file_stat;
1342 if (fstat(fileno(file), &file_stat) != 0) return NULL;
1343 bool is_regular_file = ((file_stat.st_mode & S_IFREG) != 0);
1344 if (is_regular_file) return file;
1345 fclose(file);
1346 return NULL;
1347#endif
1348}
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001349
1350
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +00001351static char* ReadChars(const char* name, int* size_out) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001352 // Release the V8 lock while reading files.
1353 v8::Unlocker unlocker(Isolate::GetCurrent());
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001354 FILE* file = FOpen(name, "rb");
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001355 if (file == NULL) return NULL;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001356
1357 fseek(file, 0, SEEK_END);
1358 int size = ftell(file);
1359 rewind(file);
1360
1361 char* chars = new char[size + 1];
1362 chars[size] = '\0';
1363 for (int i = 0; i < size;) {
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001364 int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001365 i += read;
1366 }
1367 fclose(file);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001368 *size_out = size;
1369 return chars;
1370}
1371
1372
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001373Handle<Value> Shell::ReadBuffer(const Arguments& args) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001374 ASSERT(sizeof(char) == sizeof(uint8_t)); // NOLINT
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001375 String::Utf8Value filename(args[0]);
1376 int length;
1377 if (*filename == NULL) {
1378 return ThrowException(String::New("Error loading file"));
1379 }
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001380
1381 uint8_t* data = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length));
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001382 if (data == NULL) {
1383 return ThrowException(String::New("Error reading file"));
1384 }
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001385 Handle<Object> buffer = Object::New();
verwaest@chromium.org37141392012-05-31 13:27:02 +00001386 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True());
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001387 Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer);
1388 persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback);
1389 persistent_buffer.MarkIndependent();
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001390 V8::AdjustAmountOfExternalAllocatedMemory(length);
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001391
1392 buffer->SetIndexedPropertiesToExternalArrayData(
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001393 data, kExternalUnsignedByteArray, length);
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001394 buffer->Set(String::New("byteLength"),
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001395 Int32::New(static_cast<int32_t>(length)), ReadOnly);
yangguo@chromium.orgcb9affa2012-05-15 12:16:38 +00001396 return buffer;
1397}
1398
1399
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001400#ifndef V8_SHARED
ager@chromium.org381abbb2009-02-25 13:23:22 +00001401static char* ReadToken(char* data, char token) {
1402 char* next = i::OS::StrChr(data, token);
1403 if (next != NULL) {
1404 *next = '\0';
1405 return (next + 1);
1406 }
1407
1408 return NULL;
1409}
1410
1411
1412static char* ReadLine(char* data) {
1413 return ReadToken(data, '\n');
1414}
1415
1416
1417static char* ReadWord(char* data) {
1418 return ReadToken(data, ' ');
1419}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001420#endif // V8_SHARED
ager@chromium.org381abbb2009-02-25 13:23:22 +00001421
1422
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001423// Reads a file into a v8 string.
1424Handle<String> Shell::ReadFile(const char* name) {
1425 int size = 0;
1426 char* chars = ReadChars(name, &size);
1427 if (chars == NULL) return Handle<String>();
1428 Handle<String> result = String::New(chars);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001429 delete[] chars;
1430 return result;
1431}
1432
1433
1434void Shell::RunShell() {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001435 Locker locker;
1436 Context::Scope context_scope(evaluation_context_);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001437 HandleScope outer_scope;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001438 Handle<String> name = String::New("(d8)");
lrn@chromium.org34e60782011-09-15 07:25:40 +00001439 console = LineEditor::Get();
1440 printf("V8 version %s [console: %s]\n", V8::GetVersion(), console->name());
lrn@chromium.org34e60782011-09-15 07:25:40 +00001441 console->Open();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001442 while (true) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001443 HandleScope inner_scope;
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001444 Handle<String> input = console->Prompt(Shell::kPrompt);
1445 if (input.IsEmpty()) break;
1446 ExecuteString(input, name, true, true);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001447 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001448 printf("\n");
1449}
1450
1451
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001452#ifndef V8_SHARED
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001453class ShellThread : public i::Thread {
1454 public:
lrn@chromium.org34e60782011-09-15 07:25:40 +00001455 // Takes ownership of the underlying char array of |files|.
1456 ShellThread(int no, char* files)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001457 : Thread("d8:ShellThread"),
1458 no_(no), files_(files) { }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001459
1460 ~ShellThread() {
1461 delete[] files_;
1462 }
1463
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001464 virtual void Run();
1465 private:
1466 int no_;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001467 char* files_;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001468};
1469
1470
1471void ShellThread::Run() {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001472 char* ptr = files_;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001473 while ((ptr != NULL) && (*ptr != '\0')) {
1474 // For each newline-separated line.
ager@chromium.org381abbb2009-02-25 13:23:22 +00001475 char* next_line = ReadLine(ptr);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001476
ager@chromium.org381abbb2009-02-25 13:23:22 +00001477 if (*ptr == '#') {
1478 // Skip comment lines.
1479 ptr = next_line;
1480 continue;
1481 }
1482
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001483 // Prepare the context for this thread.
1484 Locker locker;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001485 HandleScope outer_scope;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001486 Persistent<Context> thread_context = Shell::CreateEvaluationContext();
ager@chromium.org381abbb2009-02-25 13:23:22 +00001487 Context::Scope context_scope(thread_context);
1488
1489 while ((ptr != NULL) && (*ptr != '\0')) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001490 HandleScope inner_scope;
ager@chromium.org381abbb2009-02-25 13:23:22 +00001491 char* filename = ptr;
1492 ptr = ReadWord(ptr);
1493
1494 // Skip empty strings.
1495 if (strlen(filename) == 0) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001496 continue;
ager@chromium.org381abbb2009-02-25 13:23:22 +00001497 }
1498
1499 Handle<String> str = Shell::ReadFile(filename);
1500 if (str.IsEmpty()) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001501 printf("File '%s' not found\n", filename);
1502 Shell::Exit(1);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001503 }
1504
1505 Shell::ExecuteString(str, String::New(filename), false, false);
1506 }
1507
1508 thread_context.Dispose();
1509 ptr = next_line;
1510 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001511}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001512#endif // V8_SHARED
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001513
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001514
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001515SourceGroup::~SourceGroup() {
1516#ifndef V8_SHARED
1517 delete next_semaphore_;
1518 next_semaphore_ = NULL;
1519 delete done_semaphore_;
1520 done_semaphore_ = NULL;
1521 delete thread_;
1522 thread_ = NULL;
1523#endif // V8_SHARED
1524}
1525
1526
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001527void SourceGroup::Execute() {
1528 for (int i = begin_offset_; i < end_offset_; ++i) {
1529 const char* arg = argv_[i];
1530 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
1531 // Execute argument given to -e option directly.
1532 HandleScope handle_scope;
1533 Handle<String> file_name = String::New("unnamed");
1534 Handle<String> source = String::New(argv_[i + 1]);
1535 if (!Shell::ExecuteString(source, file_name, false, true)) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001536 Shell::Exit(1);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001537 }
1538 ++i;
1539 } else if (arg[0] == '-') {
1540 // Ignore other options. They have been parsed already.
1541 } else {
1542 // Use all other arguments as names of files to load and run.
1543 HandleScope handle_scope;
1544 Handle<String> file_name = String::New(arg);
1545 Handle<String> source = ReadFile(arg);
1546 if (source.IsEmpty()) {
1547 printf("Error reading '%s'\n", arg);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001548 Shell::Exit(1);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001549 }
1550 if (!Shell::ExecuteString(source, file_name, false, true)) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001551 Shell::Exit(1);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001552 }
1553 }
1554 }
1555}
1556
1557
1558Handle<String> SourceGroup::ReadFile(const char* name) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001559 int size;
rossberg@chromium.org400388e2012-06-06 09:29:22 +00001560 char* chars = ReadChars(name, &size);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001561 if (chars == NULL) return Handle<String>();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001562 Handle<String> result = String::New(chars, size);
1563 delete[] chars;
1564 return result;
1565}
1566
1567
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001568#ifndef V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001569i::Thread::Options SourceGroup::GetThreadOptions() {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001570 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
1571 // which is not enough to parse the big literal expressions used in tests.
1572 // The stack size should be at least StackGuard::kLimitSize + some
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001573 // OS-specific padding for thread startup code. 2Mbytes seems to be enough.
1574 return i::Thread::Options("IsolateThread", 2 * MB);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001575}
1576
1577
1578void SourceGroup::ExecuteInThread() {
1579 Isolate* isolate = Isolate::New();
1580 do {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001581 if (next_semaphore_ != NULL) next_semaphore_->Wait();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001582 {
1583 Isolate::Scope iscope(isolate);
1584 Locker lock(isolate);
1585 HandleScope scope;
1586 Persistent<Context> context = Shell::CreateEvaluationContext();
1587 {
1588 Context::Scope cscope(context);
1589 Execute();
1590 }
1591 context.Dispose();
1592 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001593 if (done_semaphore_ != NULL) done_semaphore_->Signal();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001594 } while (!Shell::options.last_run);
1595 isolate->Dispose();
1596}
1597
1598
1599void SourceGroup::StartExecuteInThread() {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001600 if (thread_ == NULL) {
1601 thread_ = new IsolateThread(this);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001602 thread_->Start();
1603 }
1604 next_semaphore_->Signal();
1605}
1606
1607
1608void SourceGroup::WaitForThread() {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00001609 if (thread_ == NULL) return;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001610 if (Shell::options.last_run) {
1611 thread_->Join();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001612 } else {
1613 done_semaphore_->Wait();
1614 }
1615}
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001616#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001617
1618
1619bool Shell::SetOptions(int argc, char* argv[]) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001620 for (int i = 0; i < argc; i++) {
1621 if (strcmp(argv[i], "--stress-opt") == 0) {
1622 options.stress_opt = true;
1623 argv[i] = NULL;
1624 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
1625 options.stress_deopt = true;
1626 argv[i] = NULL;
1627 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
1628 // No support for stressing if we can't use --always-opt.
1629 options.stress_opt = false;
1630 options.stress_deopt = false;
1631 } else if (strcmp(argv[i], "--shell") == 0) {
1632 options.interactive_shell = true;
1633 argv[i] = NULL;
1634 } else if (strcmp(argv[i], "--test") == 0) {
1635 options.test_shell = true;
1636 argv[i] = NULL;
1637 } else if (strcmp(argv[i], "--preemption") == 0) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001638#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001639 printf("D8 with shared library does not support multi-threading\n");
1640 return false;
1641#else
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001642 options.use_preemption = true;
1643 argv[i] = NULL;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001644#endif // V8_SHARED
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00001645 } else if (strcmp(argv[i], "--nopreemption") == 0) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001646#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001647 printf("D8 with shared library does not support multi-threading\n");
1648 return false;
1649#else
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001650 options.use_preemption = false;
1651 argv[i] = NULL;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001652#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001653 } else if (strcmp(argv[i], "--preemption-interval") == 0) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001654#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001655 printf("D8 with shared library does not support multi-threading\n");
1656 return false;
1657#else
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001658 if (++i < argc) {
1659 argv[i-1] = NULL;
1660 char* end = NULL;
1661 options.preemption_interval = strtol(argv[i], &end, 10); // NOLINT
1662 if (options.preemption_interval <= 0
1663 || *end != '\0'
1664 || errno == ERANGE) {
1665 printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
1666 return false;
1667 }
1668 argv[i] = NULL;
1669 } else {
1670 printf("Missing value for --preemption-interval\n");
1671 return false;
1672 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001673#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001674 } else if (strcmp(argv[i], "-f") == 0) {
1675 // Ignore any -f flags for compatibility with other stand-alone
1676 // JavaScript engines.
1677 continue;
1678 } else if (strcmp(argv[i], "--isolate") == 0) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001679#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001680 printf("D8 with shared library does not support multi-threading\n");
1681 return false;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001682#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001683 options.num_isolates++;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001684 } else if (strcmp(argv[i], "-p") == 0) {
1685#ifdef V8_SHARED
1686 printf("D8 with shared library does not support multi-threading\n");
1687 return false;
1688#else
1689 options.num_parallel_files++;
1690#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001691 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001692#ifdef V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001693 else if (strcmp(argv[i], "--dump-counters") == 0) {
1694 printf("D8 with shared library does not include counters\n");
1695 return false;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001696 } else if (strcmp(argv[i], "--debugger") == 0) {
1697 printf("Javascript debugger not included\n");
1698 return false;
1699 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001700#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001701 }
1702
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001703#ifndef V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001704 // Run parallel threads if we are not using --isolate
lrn@chromium.org34e60782011-09-15 07:25:40 +00001705 options.parallel_files = new char*[options.num_parallel_files];
1706 int parallel_files_set = 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001707 for (int i = 1; i < argc; i++) {
1708 if (argv[i] == NULL) continue;
1709 if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
1710 if (options.num_isolates > 1) {
1711 printf("-p is not compatible with --isolate\n");
1712 return false;
1713 }
1714 argv[i] = NULL;
lrn@chromium.org34e60782011-09-15 07:25:40 +00001715 i++;
1716 options.parallel_files[parallel_files_set] = argv[i];
1717 parallel_files_set++;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001718 argv[i] = NULL;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001719 }
1720 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001721 if (parallel_files_set != options.num_parallel_files) {
1722 printf("-p requires a file containing a list of files as parameter\n");
1723 return false;
1724 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001725#endif // V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001726
1727 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
1728
lrn@chromium.org34e60782011-09-15 07:25:40 +00001729 // Set up isolated source groups.
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001730 options.isolate_sources = new SourceGroup[options.num_isolates];
1731 SourceGroup* current = options.isolate_sources;
1732 current->Begin(argv, 1);
1733 for (int i = 1; i < argc; i++) {
1734 const char* str = argv[i];
1735 if (strcmp(str, "--isolate") == 0) {
1736 current->End(i);
1737 current++;
1738 current->Begin(argv, i + 1);
1739 } else if (strncmp(argv[i], "--", 2) == 0) {
1740 printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
1741 }
1742 }
1743 current->End(argc);
1744
1745 return true;
1746}
1747
1748
1749int Shell::RunMain(int argc, char* argv[]) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001750#ifndef V8_SHARED
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001751 i::List<i::Thread*> threads(1);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001752 if (options.parallel_files != NULL) {
1753 for (int i = 0; i < options.num_parallel_files; i++) {
1754 char* files = NULL;
1755 { Locker lock(Isolate::GetCurrent());
1756 int size = 0;
1757 files = ReadChars(options.parallel_files[i], &size);
1758 }
1759 if (files == NULL) {
1760 printf("File list '%s' not found\n", options.parallel_files[i]);
1761 Exit(1);
1762 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001763 ShellThread* thread = new ShellThread(threads.length(), files);
1764 thread->Start();
1765 threads.Add(thread);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001766 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00001767 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001768 for (int i = 1; i < options.num_isolates; ++i) {
1769 options.isolate_sources[i].StartExecuteInThread();
1770 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001771#endif // V8_SHARED
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001772 { // NOLINT
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001773 Locker lock;
1774 HandleScope scope;
1775 Persistent<Context> context = CreateEvaluationContext();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001776 if (options.last_run) {
1777 // Keep using the same context in the interactive shell.
1778 evaluation_context_ = context;
1779#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
1780 // If the interactive debugger is enabled make sure to activate
1781 // it before running the files passed on the command line.
1782 if (i::FLAG_debugger) {
1783 InstallUtilityScript();
1784 }
1785#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
1786 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001787 {
1788 Context::Scope cscope(context);
1789 options.isolate_sources[0].Execute();
1790 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001791 if (!options.last_run) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001792 context.Dispose();
danno@chromium.org88aa0582012-03-23 15:11:57 +00001793#if !defined(V8_SHARED)
1794 if (i::FLAG_send_idle_notification) {
1795 const int kLongIdlePauseInMs = 1000;
1796 V8::ContextDisposedNotification();
1797 V8::IdleNotification(kLongIdlePauseInMs);
1798 }
1799#endif // !V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001800 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001801
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001802#ifndef V8_SHARED
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001803 // Start preemption if threads have been created and preemption is enabled.
lrn@chromium.org34e60782011-09-15 07:25:40 +00001804 if (threads.length() > 0
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001805 && options.use_preemption) {
1806 Locker::StartPreemption(options.preemption_interval);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001807 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001808#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001809 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001810
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001811#ifndef V8_SHARED
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001812 for (int i = 1; i < options.num_isolates; ++i) {
1813 options.isolate_sources[i].WaitForThread();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001814 }
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001815
lrn@chromium.org34e60782011-09-15 07:25:40 +00001816 for (int i = 0; i < threads.length(); i++) {
1817 i::Thread* thread = threads[i];
1818 thread->Join();
1819 delete thread;
1820 }
1821
1822 if (threads.length() > 0 && options.use_preemption) {
1823 Locker lock;
1824 Locker::StopPreemption();
1825 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001826#endif // V8_SHARED
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001827 return 0;
1828}
1829
1830
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001831int Shell::Main(int argc, char* argv[]) {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001832 if (!SetOptions(argc, argv)) return 1;
1833 Initialize();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001834
1835 int result = 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001836 if (options.stress_opt || options.stress_deopt) {
1837 Testing::SetStressRunType(
1838 options.stress_opt ? Testing::kStressTypeOpt
1839 : Testing::kStressTypeDeopt);
1840 int stress_runs = Testing::GetStressRuns();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001841 for (int i = 0; i < stress_runs && result == 0; i++) {
1842 printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001843 Testing::PrepareStressRun(i);
1844 options.last_run = (i == stress_runs - 1);
1845 result = RunMain(argc, argv);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001846 }
1847 printf("======== Full Deoptimization =======\n");
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001848 Testing::DeoptimizeAll();
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00001849#if !defined(V8_SHARED)
1850 } else if (i::FLAG_stress_runs > 0) {
1851 int stress_runs = i::FLAG_stress_runs;
1852 for (int i = 0; i < stress_runs && result == 0; i++) {
1853 printf("============ Run %d/%d ============\n", i + 1, stress_runs);
danno@chromium.org88aa0582012-03-23 15:11:57 +00001854 options.last_run = (i == stress_runs - 1);
jkummerow@chromium.org1145ef82012-02-02 16:21:15 +00001855 result = RunMain(argc, argv);
1856 }
1857#endif
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001858 } else {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001859 result = RunMain(argc, argv);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001860 }
1861
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00001862
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001863#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
ager@chromium.org04921a82011-06-27 13:21:41 +00001864 // Run remote debugger if requested, but never on --test
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001865 if (i::FLAG_remote_debugger && !options.test_shell) {
ager@chromium.org04921a82011-06-27 13:21:41 +00001866 InstallUtilityScript();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001867 RunRemoteDebugger(i::FLAG_debugger_port);
1868 return 0;
1869 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001870#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001871
ager@chromium.org04921a82011-06-27 13:21:41 +00001872 // Run interactive shell if explicitly requested or if no script has been
1873 // executed, but never on --test
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001874
1875 if (( options.interactive_shell
1876 || !options.script_executed )
1877 && !options.test_shell ) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001878#if !defined(V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
1879 if (!i::FLAG_debugger) {
1880 InstallUtilityScript();
1881 }
1882#endif // !V8_SHARED && ENABLE_DEBUGGER_SUPPORT
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001883 RunShell();
1884 }
1885
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001886 V8::Dispose();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001887
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00001888#ifndef V8_SHARED
1889 OnExit();
1890#endif // V8_SHARED
1891
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001892 return result;
1893}
1894
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001895} // namespace v8
1896
1897
danno@chromium.org40cb8782011-05-25 07:58:50 +00001898#ifndef GOOGLE3
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001899int main(int argc, char* argv[]) {
1900 return v8::Shell::Main(argc, argv);
1901}
danno@chromium.org40cb8782011-05-25 07:58:50 +00001902#endif