OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 15 matching lines...) Expand all Loading... |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include <v8.h> | 28 #include <v8.h> |
29 #include <v8-testing.h> | 29 #include <v8-testing.h> |
30 #include <assert.h> | 30 #include <assert.h> |
31 #include <fcntl.h> | 31 #include <fcntl.h> |
32 #include <string.h> | 32 #include <string.h> |
33 #include <stdio.h> | 33 #include <stdio.h> |
34 #include <stdlib.h> | 34 #include <stdlib.h> |
35 | 35 |
| 36 #include "../src/v8.h" |
36 | 37 |
| 38 // TODO(isolates): |
| 39 // o Either use V8 internal platform stuff for every platform or |
| 40 // re-implement it. |
| 41 // o Do not assume not WIN32 implies pthreads. |
| 42 #ifndef WIN32 |
| 43 #include <pthread.h> // NOLINT |
| 44 #include <unistd.h> // NOLINT |
| 45 #endif |
| 46 |
| 47 static void ExitShell(int exit_code) { |
| 48 // Use _exit instead of exit to avoid races between isolate |
| 49 // threads and static destructors. |
| 50 fflush(stdout); |
| 51 fflush(stderr); |
| 52 _exit(exit_code); |
| 53 } |
| 54 |
| 55 v8::Persistent<v8::Context> CreateShellContext(); |
37 void RunShell(v8::Handle<v8::Context> context); | 56 void RunShell(v8::Handle<v8::Context> context); |
38 bool ExecuteString(v8::Handle<v8::String> source, | 57 bool ExecuteString(v8::Handle<v8::String> source, |
39 v8::Handle<v8::Value> name, | 58 v8::Handle<v8::Value> name, |
40 bool print_result, | 59 bool print_result, |
41 bool report_exceptions); | 60 bool report_exceptions); |
42 v8::Handle<v8::Value> Print(const v8::Arguments& args); | 61 v8::Handle<v8::Value> Print(const v8::Arguments& args); |
43 v8::Handle<v8::Value> Read(const v8::Arguments& args); | 62 v8::Handle<v8::Value> Read(const v8::Arguments& args); |
44 v8::Handle<v8::Value> Load(const v8::Arguments& args); | 63 v8::Handle<v8::Value> Load(const v8::Arguments& args); |
45 v8::Handle<v8::Value> Quit(const v8::Arguments& args); | 64 v8::Handle<v8::Value> Quit(const v8::Arguments& args); |
46 v8::Handle<v8::Value> Version(const v8::Arguments& args); | 65 v8::Handle<v8::Value> Version(const v8::Arguments& args); |
47 v8::Handle<v8::String> ReadFile(const char* name); | 66 v8::Handle<v8::String> ReadFile(const char* name); |
48 void ReportException(v8::TryCatch* handler); | 67 void ReportException(v8::TryCatch* handler); |
49 | 68 |
50 | 69 |
| 70 #ifndef WIN32 |
| 71 void* IsolateThreadEntry(void* arg); |
| 72 #endif |
| 73 |
| 74 static bool last_run = true; |
| 75 |
| 76 class SourceGroup { |
| 77 public: |
| 78 SourceGroup() : argv_(NULL), |
| 79 begin_offset_(0), |
| 80 end_offset_(0), |
| 81 next_semaphore_(NULL), |
| 82 done_semaphore_(NULL) { |
| 83 #ifndef WIN32 |
| 84 next_semaphore_ = v8::internal::OS::CreateSemaphore(0); |
| 85 done_semaphore_ = v8::internal::OS::CreateSemaphore(0); |
| 86 thread_ = 0; |
| 87 #endif |
| 88 } |
| 89 |
| 90 void Begin(char** argv, int offset) { |
| 91 argv_ = const_cast<const char**>(argv); |
| 92 begin_offset_ = offset; |
| 93 } |
| 94 |
| 95 void End(int offset) { end_offset_ = offset; } |
| 96 |
| 97 void Execute() { |
| 98 for (int i = begin_offset_; i < end_offset_; ++i) { |
| 99 const char* arg = argv_[i]; |
| 100 if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) { |
| 101 // Execute argument given to -e option directly. |
| 102 v8::HandleScope handle_scope; |
| 103 v8::Handle<v8::String> file_name = v8::String::New("unnamed"); |
| 104 v8::Handle<v8::String> source = v8::String::New(argv_[i + 1]); |
| 105 if (!ExecuteString(source, file_name, false, true)) { |
| 106 ExitShell(1); |
| 107 return; |
| 108 } |
| 109 ++i; |
| 110 } else if (arg[0] == '-') { |
| 111 // Ignore other options. They have been parsed already. |
| 112 } else { |
| 113 // Use all other arguments as names of files to load and run. |
| 114 v8::HandleScope handle_scope; |
| 115 v8::Handle<v8::String> file_name = v8::String::New(arg); |
| 116 v8::Handle<v8::String> source = ReadFile(arg); |
| 117 if (source.IsEmpty()) { |
| 118 printf("Error reading '%s'\n", arg); |
| 119 } |
| 120 if (!ExecuteString(source, file_name, false, true)) { |
| 121 ExitShell(1); |
| 122 return; |
| 123 } |
| 124 } |
| 125 } |
| 126 } |
| 127 |
| 128 #ifdef WIN32 |
| 129 void StartExecuteInThread() { ExecuteInThread(); } |
| 130 void WaitForThread() {} |
| 131 |
| 132 #else |
| 133 void StartExecuteInThread() { |
| 134 if (thread_ == 0) { |
| 135 pthread_attr_t attr; |
| 136 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less |
| 137 // which is not enough to parse the big literal expressions used in tests. |
| 138 // The stack size should be at least StackGuard::kLimitSize + some |
| 139 // OS-specific padding for thread startup code. |
| 140 size_t stacksize = 2 << 20; // 2 Mb seems to be enough |
| 141 pthread_attr_init(&attr); |
| 142 pthread_attr_setstacksize(&attr, stacksize); |
| 143 int error = pthread_create(&thread_, &attr, &IsolateThreadEntry, this); |
| 144 if (error != 0) { |
| 145 fprintf(stderr, "Error creating isolate thread.\n"); |
| 146 ExitShell(1); |
| 147 } |
| 148 } |
| 149 next_semaphore_->Signal(); |
| 150 } |
| 151 |
| 152 void WaitForThread() { |
| 153 if (thread_ == 0) return; |
| 154 if (last_run) { |
| 155 pthread_join(thread_, NULL); |
| 156 thread_ = 0; |
| 157 } else { |
| 158 done_semaphore_->Wait(); |
| 159 } |
| 160 } |
| 161 #endif // WIN32 |
| 162 |
| 163 private: |
| 164 void ExecuteInThread() { |
| 165 v8::Isolate* isolate = v8::Isolate::New(); |
| 166 do { |
| 167 if (next_semaphore_ != NULL) next_semaphore_->Wait(); |
| 168 { |
| 169 v8::Isolate::Scope iscope(isolate); |
| 170 v8::HandleScope scope; |
| 171 v8::Persistent<v8::Context> context = CreateShellContext(); |
| 172 { |
| 173 v8::Context::Scope cscope(context); |
| 174 Execute(); |
| 175 } |
| 176 context.Dispose(); |
| 177 } |
| 178 if (done_semaphore_ != NULL) done_semaphore_->Signal(); |
| 179 } while (!last_run); |
| 180 isolate->Dispose(); |
| 181 } |
| 182 |
| 183 const char** argv_; |
| 184 int begin_offset_; |
| 185 int end_offset_; |
| 186 v8::internal::Semaphore* next_semaphore_; |
| 187 v8::internal::Semaphore* done_semaphore_; |
| 188 #ifndef WIN32 |
| 189 pthread_t thread_; |
| 190 #endif |
| 191 |
| 192 friend void* IsolateThreadEntry(void* arg); |
| 193 }; |
| 194 |
| 195 #ifndef WIN32 |
| 196 void* IsolateThreadEntry(void* arg) { |
| 197 reinterpret_cast<SourceGroup*>(arg)->ExecuteInThread(); |
| 198 return NULL; |
| 199 } |
| 200 #endif |
| 201 |
| 202 |
| 203 static SourceGroup* isolate_sources = NULL; |
| 204 |
| 205 |
51 int RunMain(int argc, char* argv[]) { | 206 int RunMain(int argc, char* argv[]) { |
| 207 v8::V8::SetFlagsFromCommandLine(&argc, argv, true); |
52 v8::HandleScope handle_scope; | 208 v8::HandleScope handle_scope; |
53 // Create a template for the global object. | 209 v8::Persistent<v8::Context> context = CreateShellContext(); |
54 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); | 210 // Enter the newly created execution environment. |
55 // Bind the global 'print' function to the C++ Print callback. | 211 context->Enter(); |
56 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print)); | |
57 // Bind the global 'read' function to the C++ Read callback. | |
58 global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read)); | |
59 // Bind the global 'load' function to the C++ Load callback. | |
60 global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load)); | |
61 // Bind the 'quit' function | |
62 global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit)); | |
63 // Bind the 'version' function | |
64 global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version)); | |
65 // Create a new execution environment containing the built-in | |
66 // functions | |
67 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global); | |
68 if (context.IsEmpty()) { | 212 if (context.IsEmpty()) { |
69 printf("Error creating context\n"); | 213 printf("Error creating context\n"); |
70 return 1; | 214 return 1; |
71 } | 215 } |
72 | 216 |
73 bool run_shell = (argc == 1); | 217 bool run_shell = (argc == 1); |
| 218 int num_isolates = 1; |
74 for (int i = 1; i < argc; i++) { | 219 for (int i = 1; i < argc; i++) { |
75 // Enter the execution environment before evaluating any code. | 220 if (strcmp(argv[i], "--isolate") == 0) ++num_isolates; |
76 v8::Context::Scope context_scope(context); | 221 } |
77 const char* str = argv[i]; | 222 if (isolate_sources == NULL) { |
78 if (strcmp(str, "--shell") == 0) { | 223 isolate_sources = new SourceGroup[num_isolates]; |
79 run_shell = true; | 224 SourceGroup* current = isolate_sources; |
80 } else if (strcmp(str, "-f") == 0) { | 225 current->Begin(argv, 1); |
81 // Ignore any -f flags for compatibility with the other stand- | 226 for (int i = 1; i < argc; i++) { |
82 // alone JavaScript engines. | 227 const char* str = argv[i]; |
83 continue; | 228 if (strcmp(str, "--isolate") == 0) { |
84 } else if (strncmp(str, "--", 2) == 0) { | 229 current->End(i); |
85 printf("Warning: unknown flag %s.\nTry --help for options\n", str); | 230 current++; |
86 } else if (strcmp(str, "-e") == 0 && i + 1 < argc) { | 231 current->Begin(argv, i + 1); |
87 // Execute argument given to -e option directly | 232 } else if (strcmp(str, "--shell") == 0) { |
88 v8::HandleScope handle_scope; | 233 run_shell = true; |
89 v8::Handle<v8::String> file_name = v8::String::New("unnamed"); | 234 } else if (strcmp(str, "-f") == 0) { |
90 v8::Handle<v8::String> source = v8::String::New(argv[i + 1]); | 235 // Ignore any -f flags for compatibility with the other stand- |
91 if (!ExecuteString(source, file_name, false, true)) | 236 // alone JavaScript engines. |
92 return 1; | 237 continue; |
93 i++; | 238 } else if (strncmp(str, "--", 2) == 0) { |
94 } else { | 239 printf("Warning: unknown flag %s.\nTry --help for options\n", str); |
95 // Use all other arguments as names of files to load and run. | |
96 v8::HandleScope handle_scope; | |
97 v8::Handle<v8::String> file_name = v8::String::New(str); | |
98 v8::Handle<v8::String> source = ReadFile(str); | |
99 if (source.IsEmpty()) { | |
100 printf("Error reading '%s'\n", str); | |
101 return 1; | |
102 } | 240 } |
103 if (!ExecuteString(source, file_name, false, true)) | |
104 return 1; | |
105 } | 241 } |
| 242 current->End(argc); |
106 } | 243 } |
| 244 for (int i = 1; i < num_isolates; ++i) { |
| 245 isolate_sources[i].StartExecuteInThread(); |
| 246 } |
| 247 isolate_sources[0].Execute(); |
107 if (run_shell) RunShell(context); | 248 if (run_shell) RunShell(context); |
| 249 for (int i = 1; i < num_isolates; ++i) { |
| 250 isolate_sources[i].WaitForThread(); |
| 251 } |
| 252 if (last_run) { |
| 253 delete[] isolate_sources; |
| 254 isolate_sources = NULL; |
| 255 } |
| 256 context->Exit(); |
108 context.Dispose(); | 257 context.Dispose(); |
109 return 0; | 258 return 0; |
110 } | 259 } |
111 | 260 |
112 | 261 |
113 int main(int argc, char* argv[]) { | 262 int main(int argc, char* argv[]) { |
114 // Figure out if we're requested to stress the optimization | 263 // Figure out if we're requested to stress the optimization |
115 // infrastructure by running tests multiple times and forcing | 264 // infrastructure by running tests multiple times and forcing |
116 // optimization in the last run. | 265 // optimization in the last run. |
117 bool FLAG_stress_opt = false; | 266 bool FLAG_stress_opt = false; |
(...skipping 17 matching lines...) Expand all Loading... |
135 int result = 0; | 284 int result = 0; |
136 if (FLAG_stress_opt || FLAG_stress_deopt) { | 285 if (FLAG_stress_opt || FLAG_stress_deopt) { |
137 v8::Testing::SetStressRunType(FLAG_stress_opt | 286 v8::Testing::SetStressRunType(FLAG_stress_opt |
138 ? v8::Testing::kStressTypeOpt | 287 ? v8::Testing::kStressTypeOpt |
139 : v8::Testing::kStressTypeDeopt); | 288 : v8::Testing::kStressTypeDeopt); |
140 int stress_runs = v8::Testing::GetStressRuns(); | 289 int stress_runs = v8::Testing::GetStressRuns(); |
141 for (int i = 0; i < stress_runs && result == 0; i++) { | 290 for (int i = 0; i < stress_runs && result == 0; i++) { |
142 printf("============ Stress %d/%d ============\n", | 291 printf("============ Stress %d/%d ============\n", |
143 i + 1, stress_runs); | 292 i + 1, stress_runs); |
144 v8::Testing::PrepareStressRun(i); | 293 v8::Testing::PrepareStressRun(i); |
| 294 last_run = (i == stress_runs - 1); |
145 result = RunMain(argc, argv); | 295 result = RunMain(argc, argv); |
146 } | 296 } |
147 printf("======== Full Deoptimization =======\n"); | 297 printf("======== Full Deoptimization =======\n"); |
148 v8::Testing::DeoptimizeAll(); | 298 v8::Testing::DeoptimizeAll(); |
149 } else { | 299 } else { |
150 result = RunMain(argc, argv); | 300 result = RunMain(argc, argv); |
151 } | 301 } |
152 v8::V8::Dispose(); | 302 v8::V8::Dispose(); |
153 return result; | 303 return result; |
154 } | 304 } |
155 | 305 |
156 | 306 |
157 // Extracts a C string from a V8 Utf8Value. | 307 // Extracts a C string from a V8 Utf8Value. |
158 const char* ToCString(const v8::String::Utf8Value& value) { | 308 const char* ToCString(const v8::String::Utf8Value& value) { |
159 return *value ? *value : "<string conversion failed>"; | 309 return *value ? *value : "<string conversion failed>"; |
160 } | 310 } |
161 | 311 |
162 | 312 |
| 313 // Creates a new execution environment containing the built-in |
| 314 // functions. |
| 315 v8::Persistent<v8::Context> CreateShellContext() { |
| 316 // Create a template for the global object. |
| 317 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); |
| 318 // Bind the global 'print' function to the C++ Print callback. |
| 319 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print)); |
| 320 // Bind the global 'read' function to the C++ Read callback. |
| 321 global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read)); |
| 322 // Bind the global 'load' function to the C++ Load callback. |
| 323 global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load)); |
| 324 // Bind the 'quit' function |
| 325 global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit)); |
| 326 // Bind the 'version' function |
| 327 global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version)); |
| 328 return v8::Context::New(NULL, global); |
| 329 } |
| 330 |
| 331 |
163 // The callback that is invoked by v8 whenever the JavaScript 'print' | 332 // The callback that is invoked by v8 whenever the JavaScript 'print' |
164 // function is called. Prints its arguments on stdout separated by | 333 // function is called. Prints its arguments on stdout separated by |
165 // spaces and ending with a newline. | 334 // spaces and ending with a newline. |
166 v8::Handle<v8::Value> Print(const v8::Arguments& args) { | 335 v8::Handle<v8::Value> Print(const v8::Arguments& args) { |
167 bool first = true; | 336 bool first = true; |
168 for (int i = 0; i < args.Length(); i++) { | 337 for (int i = 0; i < args.Length(); i++) { |
169 v8::HandleScope handle_scope; | 338 v8::HandleScope handle_scope; |
170 if (first) { | 339 if (first) { |
171 first = false; | 340 first = false; |
172 } else { | 341 } else { |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 return v8::Undefined(); | 391 return v8::Undefined(); |
223 } | 392 } |
224 | 393 |
225 | 394 |
226 // The callback that is invoked by v8 whenever the JavaScript 'quit' | 395 // The callback that is invoked by v8 whenever the JavaScript 'quit' |
227 // function is called. Quits. | 396 // function is called. Quits. |
228 v8::Handle<v8::Value> Quit(const v8::Arguments& args) { | 397 v8::Handle<v8::Value> Quit(const v8::Arguments& args) { |
229 // If not arguments are given args[0] will yield undefined which | 398 // If not arguments are given args[0] will yield undefined which |
230 // converts to the integer value 0. | 399 // converts to the integer value 0. |
231 int exit_code = args[0]->Int32Value(); | 400 int exit_code = args[0]->Int32Value(); |
232 exit(exit_code); | 401 ExitShell(exit_code); |
233 return v8::Undefined(); | 402 return v8::Undefined(); |
234 } | 403 } |
235 | 404 |
236 | 405 |
237 v8::Handle<v8::Value> Version(const v8::Arguments& args) { | 406 v8::Handle<v8::Value> Version(const v8::Arguments& args) { |
238 return v8::String::New(v8::V8::GetVersion()); | 407 return v8::String::New(v8::V8::GetVersion()); |
239 } | 408 } |
240 | 409 |
241 | 410 |
242 // Reads a file into a v8 string. | 411 // Reads a file into a v8 string. |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 printf("^"); | 516 printf("^"); |
348 } | 517 } |
349 printf("\n"); | 518 printf("\n"); |
350 v8::String::Utf8Value stack_trace(try_catch->StackTrace()); | 519 v8::String::Utf8Value stack_trace(try_catch->StackTrace()); |
351 if (stack_trace.length() > 0) { | 520 if (stack_trace.length() > 0) { |
352 const char* stack_trace_string = ToCString(stack_trace); | 521 const char* stack_trace_string = ToCString(stack_trace); |
353 printf("%s\n", stack_trace_string); | 522 printf("%s\n", stack_trace_string); |
354 } | 523 } |
355 } | 524 } |
356 } | 525 } |
OLD | NEW |