blob: 6b67df6c6c56467611d4277426df9af250e07574 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <v8.h>
Ben Murdochb0fe1622011-05-05 13:52:32 +010029#include <v8-testing.h>
Steve Blocka7e24c12009-10-30 11:49:00 +000030#include <fcntl.h>
31#include <string.h>
32#include <stdio.h>
33#include <stdlib.h>
34
35
36void RunShell(v8::Handle<v8::Context> context);
37bool ExecuteString(v8::Handle<v8::String> source,
38 v8::Handle<v8::Value> name,
39 bool print_result,
40 bool report_exceptions);
41v8::Handle<v8::Value> Print(const v8::Arguments& args);
42v8::Handle<v8::Value> Read(const v8::Arguments& args);
43v8::Handle<v8::Value> Load(const v8::Arguments& args);
44v8::Handle<v8::Value> Quit(const v8::Arguments& args);
45v8::Handle<v8::Value> Version(const v8::Arguments& args);
46v8::Handle<v8::String> ReadFile(const char* name);
47void ReportException(v8::TryCatch* handler);
48
49
50int RunMain(int argc, char* argv[]) {
Steve Blocka7e24c12009-10-30 11:49:00 +000051 v8::HandleScope handle_scope;
52 // Create a template for the global object.
53 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
54 // Bind the global 'print' function to the C++ Print callback.
55 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
56 // Bind the global 'read' function to the C++ Read callback.
57 global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
58 // Bind the global 'load' function to the C++ Load callback.
59 global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
60 // Bind the 'quit' function
61 global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
62 // Bind the 'version' function
63 global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
64 // Create a new execution environment containing the built-in
65 // functions
Ben Murdochb0fe1622011-05-05 13:52:32 +010066 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
Steve Blocka7e24c12009-10-30 11:49:00 +000067 bool run_shell = (argc == 1);
68 for (int i = 1; i < argc; i++) {
Ben Murdochb0fe1622011-05-05 13:52:32 +010069 // Enter the execution environment before evaluating any code.
70 v8::Context::Scope context_scope(context);
Steve Blocka7e24c12009-10-30 11:49:00 +000071 const char* str = argv[i];
72 if (strcmp(str, "--shell") == 0) {
73 run_shell = true;
74 } else if (strcmp(str, "-f") == 0) {
75 // Ignore any -f flags for compatibility with the other stand-
76 // alone JavaScript engines.
77 continue;
78 } else if (strncmp(str, "--", 2) == 0) {
79 printf("Warning: unknown flag %s.\nTry --help for options\n", str);
80 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
81 // Execute argument given to -e option directly
82 v8::HandleScope handle_scope;
83 v8::Handle<v8::String> file_name = v8::String::New("unnamed");
84 v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
85 if (!ExecuteString(source, file_name, false, true))
86 return 1;
87 i++;
88 } else {
89 // Use all other arguments as names of files to load and run.
90 v8::HandleScope handle_scope;
91 v8::Handle<v8::String> file_name = v8::String::New(str);
92 v8::Handle<v8::String> source = ReadFile(str);
93 if (source.IsEmpty()) {
94 printf("Error reading '%s'\n", str);
95 return 1;
96 }
97 if (!ExecuteString(source, file_name, false, true))
98 return 1;
99 }
100 }
101 if (run_shell) RunShell(context);
Ben Murdochb0fe1622011-05-05 13:52:32 +0100102 context.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +0000103 return 0;
104}
105
106
107int main(int argc, char* argv[]) {
Ben Murdochb0fe1622011-05-05 13:52:32 +0100108 // Figure out if we're requested to stress the optimization
109 // infrastructure by running tests multiple times and forcing
110 // optimization in the last run.
111 bool FLAG_stress_opt = false;
112 bool FLAG_stress_deopt = false;
113 for (int i = 0; i < argc; i++) {
114 if (strcmp(argv[i], "--stress-opt") == 0) {
115 FLAG_stress_opt = true;
116 argv[i] = NULL;
117 } else if (strcmp(argv[i], "--stress-deopt") == 0) {
118 FLAG_stress_deopt = true;
119 argv[i] = NULL;
120 } else if (strcmp(argv[i], "--noalways-opt") == 0) {
121 // No support for stressing if we can't use --always-opt.
122 FLAG_stress_opt = false;
123 FLAG_stress_deopt = false;
124 break;
125 }
126 }
127
128 v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
129 int result = 0;
130 if (FLAG_stress_opt || FLAG_stress_deopt) {
131 v8::Testing::SetStressRunType(FLAG_stress_opt
132 ? v8::Testing::kStressTypeOpt
133 : v8::Testing::kStressTypeDeopt);
134 int stress_runs = v8::Testing::GetStressRuns();
135 for (int i = 0; i < stress_runs && result == 0; i++) {
136 printf("============ Stress %d/%d ============\n",
137 i + 1, stress_runs);
138 v8::Testing::PrepareStressRun(i);
139 result = RunMain(argc, argv);
140 }
141 } else {
142 result = RunMain(argc, argv);
143 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000144 v8::V8::Dispose();
145 return result;
146}
147
148
149// Extracts a C string from a V8 Utf8Value.
150const char* ToCString(const v8::String::Utf8Value& value) {
151 return *value ? *value : "<string conversion failed>";
152}
153
154
155// The callback that is invoked by v8 whenever the JavaScript 'print'
156// function is called. Prints its arguments on stdout separated by
157// spaces and ending with a newline.
158v8::Handle<v8::Value> Print(const v8::Arguments& args) {
159 bool first = true;
160 for (int i = 0; i < args.Length(); i++) {
161 v8::HandleScope handle_scope;
162 if (first) {
163 first = false;
164 } else {
165 printf(" ");
166 }
167 v8::String::Utf8Value str(args[i]);
168 const char* cstr = ToCString(str);
169 printf("%s", cstr);
170 }
171 printf("\n");
172 fflush(stdout);
173 return v8::Undefined();
174}
175
176
177// The callback that is invoked by v8 whenever the JavaScript 'read'
178// function is called. This function loads the content of the file named in
179// the argument into a JavaScript string.
180v8::Handle<v8::Value> Read(const v8::Arguments& args) {
181 if (args.Length() != 1) {
182 return v8::ThrowException(v8::String::New("Bad parameters"));
183 }
184 v8::String::Utf8Value file(args[0]);
185 if (*file == NULL) {
186 return v8::ThrowException(v8::String::New("Error loading file"));
187 }
188 v8::Handle<v8::String> source = ReadFile(*file);
189 if (source.IsEmpty()) {
190 return v8::ThrowException(v8::String::New("Error loading file"));
191 }
192 return source;
193}
194
195
196// The callback that is invoked by v8 whenever the JavaScript 'load'
197// function is called. Loads, compiles and executes its argument
198// JavaScript file.
199v8::Handle<v8::Value> Load(const v8::Arguments& args) {
200 for (int i = 0; i < args.Length(); i++) {
201 v8::HandleScope handle_scope;
202 v8::String::Utf8Value file(args[i]);
203 if (*file == NULL) {
204 return v8::ThrowException(v8::String::New("Error loading file"));
205 }
206 v8::Handle<v8::String> source = ReadFile(*file);
207 if (source.IsEmpty()) {
208 return v8::ThrowException(v8::String::New("Error loading file"));
209 }
210 if (!ExecuteString(source, v8::String::New(*file), false, false)) {
211 return v8::ThrowException(v8::String::New("Error executing file"));
212 }
213 }
214 return v8::Undefined();
215}
216
217
218// The callback that is invoked by v8 whenever the JavaScript 'quit'
219// function is called. Quits.
220v8::Handle<v8::Value> Quit(const v8::Arguments& args) {
221 // If not arguments are given args[0] will yield undefined which
222 // converts to the integer value 0.
223 int exit_code = args[0]->Int32Value();
224 exit(exit_code);
225 return v8::Undefined();
226}
227
228
229v8::Handle<v8::Value> Version(const v8::Arguments& args) {
230 return v8::String::New(v8::V8::GetVersion());
231}
232
233
234// Reads a file into a v8 string.
235v8::Handle<v8::String> ReadFile(const char* name) {
236 FILE* file = fopen(name, "rb");
237 if (file == NULL) return v8::Handle<v8::String>();
238
239 fseek(file, 0, SEEK_END);
240 int size = ftell(file);
241 rewind(file);
242
243 char* chars = new char[size + 1];
244 chars[size] = '\0';
245 for (int i = 0; i < size;) {
246 int read = fread(&chars[i], 1, size - i, file);
247 i += read;
248 }
249 fclose(file);
250 v8::Handle<v8::String> result = v8::String::New(chars, size);
251 delete[] chars;
252 return result;
253}
254
255
256// The read-eval-execute loop of the shell.
257void RunShell(v8::Handle<v8::Context> context) {
258 printf("V8 version %s\n", v8::V8::GetVersion());
259 static const int kBufferSize = 256;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100260 // Enter the execution environment before evaluating any code.
261 v8::Context::Scope context_scope(context);
Steve Blocka7e24c12009-10-30 11:49:00 +0000262 while (true) {
263 char buffer[kBufferSize];
264 printf("> ");
265 char* str = fgets(buffer, kBufferSize, stdin);
266 if (str == NULL) break;
267 v8::HandleScope handle_scope;
268 ExecuteString(v8::String::New(str),
269 v8::String::New("(shell)"),
270 true,
271 true);
272 }
273 printf("\n");
274}
275
276
277// Executes a string within the current v8 context.
278bool ExecuteString(v8::Handle<v8::String> source,
279 v8::Handle<v8::Value> name,
280 bool print_result,
281 bool report_exceptions) {
282 v8::HandleScope handle_scope;
283 v8::TryCatch try_catch;
284 v8::Handle<v8::Script> script = v8::Script::Compile(source, name);
285 if (script.IsEmpty()) {
286 // Print errors that happened during compilation.
287 if (report_exceptions)
288 ReportException(&try_catch);
289 return false;
290 } else {
291 v8::Handle<v8::Value> result = script->Run();
292 if (result.IsEmpty()) {
293 // Print errors that happened during execution.
294 if (report_exceptions)
295 ReportException(&try_catch);
296 return false;
297 } else {
298 if (print_result && !result->IsUndefined()) {
299 // If all went well and the result wasn't undefined then print
300 // the returned value.
301 v8::String::Utf8Value str(result);
302 const char* cstr = ToCString(str);
303 printf("%s\n", cstr);
304 }
305 return true;
306 }
307 }
308}
309
310
311void ReportException(v8::TryCatch* try_catch) {
312 v8::HandleScope handle_scope;
313 v8::String::Utf8Value exception(try_catch->Exception());
314 const char* exception_string = ToCString(exception);
315 v8::Handle<v8::Message> message = try_catch->Message();
316 if (message.IsEmpty()) {
317 // V8 didn't provide any extra information about this error; just
318 // print the exception.
319 printf("%s\n", exception_string);
320 } else {
321 // Print (filename):(line number): (message).
322 v8::String::Utf8Value filename(message->GetScriptResourceName());
323 const char* filename_string = ToCString(filename);
324 int linenum = message->GetLineNumber();
325 printf("%s:%i: %s\n", filename_string, linenum, exception_string);
326 // Print line of source code.
327 v8::String::Utf8Value sourceline(message->GetSourceLine());
328 const char* sourceline_string = ToCString(sourceline);
329 printf("%s\n", sourceline_string);
330 // Print wavy underline (GetUnderline is deprecated).
331 int start = message->GetStartColumn();
332 for (int i = 0; i < start; i++) {
333 printf(" ");
334 }
335 int end = message->GetEndColumn();
336 for (int i = start; i < end; i++) {
337 printf("^");
338 }
339 printf("\n");
Kristian Monsen25f61362010-05-21 11:50:48 +0100340 v8::String::Utf8Value stack_trace(try_catch->StackTrace());
341 if (stack_trace.length() > 0) {
342 const char* stack_trace_string = ToCString(stack_trace);
343 printf("%s\n", stack_trace_string);
344 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000345 }
346}