| 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
| 15 // | 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 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 <fcntl.h> | 30 #include <fcntl.h> |
| 30 #include <string.h> | 31 #include <string.h> |
| 31 #include <stdio.h> | 32 #include <stdio.h> |
| 32 #include <stdlib.h> | 33 #include <stdlib.h> |
| 33 | 34 |
| 35 #include "../src/v8.h" |
| 36 |
| 34 // TODO(isolates): | 37 // TODO(isolates): |
| 35 // o Add thread implementation for more platforms. | 38 // o Either use V8 internal platform stuff for every platform or |
| 39 // re-implement it. |
| 36 // o Do not assume not WIN32 implies pthreads. | 40 // o Do not assume not WIN32 implies pthreads. |
| 37 #ifndef WIN32 | 41 #ifndef WIN32 |
| 38 #include <pthread.h> | 42 #include <pthread.h> // NOLINT |
| 39 #endif | 43 #endif |
| 40 | 44 |
| 41 v8::Handle<v8::Context> CreateShellContext(); | 45 v8::Persistent<v8::Context> CreateShellContext(); |
| 42 void RunShell(v8::Handle<v8::Context> context); | 46 void RunShell(v8::Handle<v8::Context> context); |
| 43 bool ExecuteString(v8::Handle<v8::String> source, | 47 bool ExecuteString(v8::Handle<v8::String> source, |
| 44 v8::Handle<v8::Value> name, | 48 v8::Handle<v8::Value> name, |
| 45 bool print_result, | 49 bool print_result, |
| 46 bool report_exceptions); | 50 bool report_exceptions); |
| 47 v8::Handle<v8::Value> Print(const v8::Arguments& args); | 51 v8::Handle<v8::Value> Print(const v8::Arguments& args); |
| 48 v8::Handle<v8::Value> Read(const v8::Arguments& args); | 52 v8::Handle<v8::Value> Read(const v8::Arguments& args); |
| 49 v8::Handle<v8::Value> Load(const v8::Arguments& args); | 53 v8::Handle<v8::Value> Load(const v8::Arguments& args); |
| 50 v8::Handle<v8::Value> Quit(const v8::Arguments& args); | 54 v8::Handle<v8::Value> Quit(const v8::Arguments& args); |
| 51 v8::Handle<v8::Value> Version(const v8::Arguments& args); | 55 v8::Handle<v8::Value> Version(const v8::Arguments& args); |
| 52 v8::Handle<v8::String> ReadFile(const char* name); | 56 v8::Handle<v8::String> ReadFile(const char* name); |
| 53 void ReportException(v8::TryCatch* handler); | 57 void ReportException(v8::TryCatch* handler); |
| 54 | 58 |
| 55 | 59 |
| 56 #ifndef WIN32 | 60 #ifndef WIN32 |
| 57 void* IsolateThreadEntry(void* arg); | 61 void* IsolateThreadEntry(void* arg); |
| 58 #endif | 62 #endif |
| 59 | 63 |
| 64 static bool last_run = true; |
| 65 |
| 60 class SourceGroup { | 66 class SourceGroup { |
| 61 public: | 67 public: |
| 62 SourceGroup() : argv_(NULL), begin_offset_(0), end_offset_(0) { | 68 SourceGroup() : argv_(NULL), |
| 69 begin_offset_(0), |
| 70 end_offset_(0), |
| 71 next_semaphore_(NULL), |
| 72 done_semaphore_(NULL) { |
| 63 #ifndef WIN32 | 73 #ifndef WIN32 |
| 74 next_semaphore_ = v8::internal::OS::CreateSemaphore(0); |
| 75 done_semaphore_ = v8::internal::OS::CreateSemaphore(0); |
| 64 thread_ = 0; | 76 thread_ = 0; |
| 65 #endif | 77 #endif |
| 66 } | 78 } |
| 67 | 79 |
| 68 void Begin(char** argv, int offset) { | 80 void Begin(char** argv, int offset) { |
| 69 argv_ = const_cast<const char**>(argv); | 81 argv_ = const_cast<const char**>(argv); |
| 70 begin_offset_ = offset; | 82 begin_offset_ = offset; |
| 71 } | 83 } |
| 72 | 84 |
| 73 void End(int offset) { end_offset_ = offset; } | 85 void End(int offset) { end_offset_ = offset; } |
| (...skipping 28 matching lines...) Expand all Loading... |
| 102 } | 114 } |
| 103 } | 115 } |
| 104 } | 116 } |
| 105 | 117 |
| 106 #ifdef WIN32 | 118 #ifdef WIN32 |
| 107 void StartExecuteInThread() { ExecuteInThread(); } | 119 void StartExecuteInThread() { ExecuteInThread(); } |
| 108 void WaitForThread() {} | 120 void WaitForThread() {} |
| 109 | 121 |
| 110 #else | 122 #else |
| 111 void StartExecuteInThread() { | 123 void StartExecuteInThread() { |
| 112 pthread_create(&thread_, NULL, &IsolateThreadEntry, this); | 124 if (thread_ == 0) { |
| 125 pthread_attr_t attr; |
| 126 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less |
| 127 // which is not enough to parse the big literal expressions used in tests. |
| 128 // The stack size should be at least StackGuard::kLimitSize + some |
| 129 // OS-specific padding for thread startup code. |
| 130 size_t stacksize = 1024 * 1024; // 1 Mb seems to be enough |
| 131 pthread_attr_init(&attr); |
| 132 pthread_attr_setstacksize(&attr, stacksize); |
| 133 int error = pthread_create(&thread_, &attr, &IsolateThreadEntry, this); |
| 134 if (error) { |
| 135 printf("Error creating isolate thread.\n"); |
| 136 exit(1); |
| 137 } |
| 138 } |
| 139 next_semaphore_->Signal(); |
| 113 } | 140 } |
| 114 | 141 |
| 115 void WaitForThread() { | 142 void WaitForThread() { |
| 116 if (thread_ == 0) return; | 143 if (thread_ == 0) return; |
| 117 pthread_join(thread_, NULL); | 144 if (last_run) { |
| 118 thread_ = 0; | 145 pthread_join(thread_, NULL); |
| 146 thread_ = 0; |
| 147 } else { |
| 148 done_semaphore_->Wait(); |
| 149 } |
| 119 } | 150 } |
| 120 #endif // WIN32 | 151 #endif // WIN32 |
| 121 | 152 |
| 122 private: | 153 private: |
| 123 void ExecuteInThread() { | 154 void ExecuteInThread() { |
| 124 v8::Isolate* isolate = v8::Isolate::New(); | 155 v8::Isolate* isolate = v8::Isolate::New(); |
| 125 { | 156 do { |
| 126 v8::Isolate::Scope iscope(isolate); | 157 if (next_semaphore_ != NULL) next_semaphore_->Wait(); |
| 127 v8::HandleScope scope; | 158 { |
| 128 v8::Context::Scope cscope(CreateShellContext()); | 159 v8::Isolate::Scope iscope(isolate); |
| 129 Execute(); | 160 v8::HandleScope scope; |
| 130 } | 161 v8::Persistent<v8::Context> context = CreateShellContext(); |
| 162 { |
| 163 v8::Context::Scope cscope(context); |
| 164 Execute(); |
| 165 } |
| 166 context.Dispose(); |
| 167 } |
| 168 if (done_semaphore_ != NULL) done_semaphore_->Signal(); |
| 169 } while (!last_run); |
| 131 isolate->Dispose(); | 170 isolate->Dispose(); |
| 132 } | 171 } |
| 133 | 172 |
| 134 const char** argv_; | 173 const char** argv_; |
| 135 int begin_offset_; | 174 int begin_offset_; |
| 136 int end_offset_; | 175 int end_offset_; |
| 176 v8::internal::Semaphore* next_semaphore_; |
| 177 v8::internal::Semaphore* done_semaphore_; |
| 137 #ifndef WIN32 | 178 #ifndef WIN32 |
| 138 pthread_t thread_; | 179 pthread_t thread_; |
| 139 #endif | 180 #endif |
| 140 | 181 |
| 141 friend void* IsolateThreadEntry(void* arg); | 182 friend void* IsolateThreadEntry(void* arg); |
| 142 }; | 183 }; |
| 143 | 184 |
| 144 #ifndef WIN32 | 185 #ifndef WIN32 |
| 145 void* IsolateThreadEntry(void* arg) { | 186 void* IsolateThreadEntry(void* arg) { |
| 146 reinterpret_cast<SourceGroup*>(arg)->ExecuteInThread(); | 187 reinterpret_cast<SourceGroup*>(arg)->ExecuteInThread(); |
| 147 return NULL; | 188 return NULL; |
| 148 } | 189 } |
| 149 #endif | 190 #endif |
| 150 | 191 |
| 151 | 192 |
| 193 static SourceGroup* isolate_sources = NULL; |
| 194 |
| 195 |
| 152 int RunMain(int argc, char* argv[]) { | 196 int RunMain(int argc, char* argv[]) { |
| 153 v8::V8::SetFlagsFromCommandLine(&argc, argv, true); | 197 v8::V8::SetFlagsFromCommandLine(&argc, argv, true); |
| 154 v8::HandleScope handle_scope; | 198 v8::HandleScope handle_scope; |
| 155 v8::Handle<v8::Context> context = CreateShellContext(); | 199 v8::Persistent<v8::Context> context = CreateShellContext(); |
| 156 // Enter the newly created execution environment. | 200 // Enter the newly created execution environment. |
| 157 v8::Context::Scope context_scope(context); | 201 context->Enter(); |
| 158 bool run_shell = (argc == 1); | 202 bool run_shell = (argc == 1); |
| 159 int num_isolates = 1; | 203 int num_isolates = 1; |
| 160 for (int i = 1; i < argc; i++) { | 204 for (int i = 1; i < argc; i++) { |
| 161 if (strcmp(argv[i], "--isolate") == 0) ++num_isolates; | 205 if (strcmp(argv[i], "--isolate") == 0) ++num_isolates; |
| 162 } | 206 } |
| 163 SourceGroup* isolate_sources = new SourceGroup[num_isolates]; | 207 if (isolate_sources == NULL) { |
| 164 SourceGroup* current = isolate_sources; | 208 isolate_sources = new SourceGroup[num_isolates]; |
| 165 current->Begin(argv, 1); | 209 SourceGroup* current = isolate_sources; |
| 166 for (int i = 1; i < argc; i++) { | 210 current->Begin(argv, 1); |
| 167 const char* str = argv[i]; | 211 for (int i = 1; i < argc; i++) { |
| 168 if (strcmp(str, "--isolate") == 0) { | 212 const char* str = argv[i]; |
| 169 current->End(i); | 213 if (strcmp(str, "--isolate") == 0) { |
| 170 current++; | 214 current->End(i); |
| 171 current->Begin(argv, i + 1); | 215 current++; |
| 172 } else if (strcmp(str, "--shell") == 0) { | 216 current->Begin(argv, i + 1); |
| 173 run_shell = true; | 217 } else if (strcmp(str, "--shell") == 0) { |
| 174 } else if (strcmp(str, "-f") == 0) { | 218 run_shell = true; |
| 175 // Ignore any -f flags for compatibility with the other stand- | 219 } else if (strcmp(str, "-f") == 0) { |
| 176 // alone JavaScript engines. | 220 // Ignore any -f flags for compatibility with the other stand- |
| 177 continue; | 221 // alone JavaScript engines. |
| 178 } else if (strncmp(str, "--", 2) == 0) { | 222 continue; |
| 179 printf("Warning: unknown flag %s.\nTry --help for options\n", str); | 223 } else if (strncmp(str, "--", 2) == 0) { |
| 224 printf("Warning: unknown flag %s.\nTry --help for options\n", str); |
| 225 } |
| 180 } | 226 } |
| 227 current->End(argc); |
| 181 } | 228 } |
| 182 current->End(argc); | |
| 183 for (int i = 1; i < num_isolates; ++i) { | 229 for (int i = 1; i < num_isolates; ++i) { |
| 184 isolate_sources[i].StartExecuteInThread(); | 230 isolate_sources[i].StartExecuteInThread(); |
| 185 } | 231 } |
| 186 isolate_sources[0].Execute(); | 232 isolate_sources[0].Execute(); |
| 187 if (run_shell) RunShell(context); | 233 if (run_shell) RunShell(context); |
| 188 for (int i = 1; i < num_isolates; ++i) { | 234 for (int i = 1; i < num_isolates; ++i) { |
| 189 isolate_sources[i].WaitForThread(); | 235 isolate_sources[i].WaitForThread(); |
| 190 } | 236 } |
| 191 delete[] isolate_sources; | 237 if (last_run) { |
| 238 delete[] isolate_sources; |
| 239 isolate_sources = NULL; |
| 240 } |
| 241 context->Exit(); |
| 242 context.Dispose(); |
| 192 return 0; | 243 return 0; |
| 193 } | 244 } |
| 194 | 245 |
| 195 | 246 |
| 196 int main(int argc, char* argv[]) { | 247 int main(int argc, char* argv[]) { |
| 197 int result = RunMain(argc, argv); | 248 // Figure out if we're requested to stress the optimization |
| 249 // infrastructure by running tests multiple times and forcing |
| 250 // optimization in the last run. |
| 251 bool FLAG_stress_opt = false; |
| 252 bool FLAG_stress_deopt = false; |
| 253 for (int i = 0; i < argc; i++) { |
| 254 if (strcmp(argv[i], "--stress-opt") == 0) { |
| 255 FLAG_stress_opt = true; |
| 256 argv[i] = NULL; |
| 257 } else if (strcmp(argv[i], "--stress-deopt") == 0) { |
| 258 FLAG_stress_deopt = true; |
| 259 argv[i] = NULL; |
| 260 } else if (strcmp(argv[i], "--noalways-opt") == 0) { |
| 261 // No support for stressing if we can't use --always-opt. |
| 262 FLAG_stress_opt = false; |
| 263 FLAG_stress_deopt = false; |
| 264 break; |
| 265 } |
| 266 } |
| 267 |
| 268 v8::V8::SetFlagsFromCommandLine(&argc, argv, true); |
| 269 int result = 0; |
| 270 if (FLAG_stress_opt || FLAG_stress_deopt) { |
| 271 v8::Testing::SetStressRunType(FLAG_stress_opt |
| 272 ? v8::Testing::kStressTypeOpt |
| 273 : v8::Testing::kStressTypeDeopt); |
| 274 int stress_runs = v8::Testing::GetStressRuns(); |
| 275 for (int i = 0; i < stress_runs && result == 0; i++) { |
| 276 printf("============ Stress %d/%d ============\n", |
| 277 i + 1, stress_runs); |
| 278 v8::Testing::PrepareStressRun(i); |
| 279 last_run = (i == stress_runs - 1); |
| 280 result = RunMain(argc, argv); |
| 281 } |
| 282 } else { |
| 283 result = RunMain(argc, argv); |
| 284 } |
| 198 v8::V8::Dispose(); | 285 v8::V8::Dispose(); |
| 199 return result; | 286 return result; |
| 200 } | 287 } |
| 201 | 288 |
| 202 | 289 |
| 203 // Extracts a C string from a V8 Utf8Value. | 290 // Extracts a C string from a V8 Utf8Value. |
| 204 const char* ToCString(const v8::String::Utf8Value& value) { | 291 const char* ToCString(const v8::String::Utf8Value& value) { |
| 205 return *value ? *value : "<string conversion failed>"; | 292 return *value ? *value : "<string conversion failed>"; |
| 206 } | 293 } |
| 207 | 294 |
| 208 | 295 |
| 209 // Creates a new execution environment containing the built-in | 296 // Creates a new execution environment containing the built-in |
| 210 // functions. | 297 // functions. |
| 211 v8::Handle<v8::Context> CreateShellContext() { | 298 v8::Persistent<v8::Context> CreateShellContext() { |
| 212 // Create a template for the global object. | 299 // Create a template for the global object. |
| 213 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); | 300 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(); |
| 214 // Bind the global 'print' function to the C++ Print callback. | 301 // Bind the global 'print' function to the C++ Print callback. |
| 215 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print)); | 302 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print)); |
| 216 // Bind the global 'read' function to the C++ Read callback. | 303 // Bind the global 'read' function to the C++ Read callback. |
| 217 global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read)); | 304 global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read)); |
| 218 // Bind the global 'load' function to the C++ Load callback. | 305 // Bind the global 'load' function to the C++ Load callback. |
| 219 global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load)); | 306 global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load)); |
| 220 // Bind the 'quit' function | 307 // Bind the 'quit' function |
| 221 global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit)); | 308 global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit)); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 v8::Handle<v8::String> result = v8::String::New(chars, size); | 410 v8::Handle<v8::String> result = v8::String::New(chars, size); |
| 324 delete[] chars; | 411 delete[] chars; |
| 325 return result; | 412 return result; |
| 326 } | 413 } |
| 327 | 414 |
| 328 | 415 |
| 329 // The read-eval-execute loop of the shell. | 416 // The read-eval-execute loop of the shell. |
| 330 void RunShell(v8::Handle<v8::Context> context) { | 417 void RunShell(v8::Handle<v8::Context> context) { |
| 331 printf("V8 version %s\n", v8::V8::GetVersion()); | 418 printf("V8 version %s\n", v8::V8::GetVersion()); |
| 332 static const int kBufferSize = 256; | 419 static const int kBufferSize = 256; |
| 420 // Enter the execution environment before evaluating any code. |
| 421 v8::Context::Scope context_scope(context); |
| 333 while (true) { | 422 while (true) { |
| 334 char buffer[kBufferSize]; | 423 char buffer[kBufferSize]; |
| 335 printf("> "); | 424 printf("> "); |
| 336 char* str = fgets(buffer, kBufferSize, stdin); | 425 char* str = fgets(buffer, kBufferSize, stdin); |
| 337 if (str == NULL) break; | 426 if (str == NULL) break; |
| 338 v8::HandleScope handle_scope; | 427 v8::HandleScope handle_scope; |
| 339 ExecuteString(v8::String::New(str), | 428 ExecuteString(v8::String::New(str), |
| 340 v8::String::New("(shell)"), | 429 v8::String::New("(shell)"), |
| 341 true, | 430 true, |
| 342 true); | 431 true); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 printf("^"); | 497 printf("^"); |
| 409 } | 498 } |
| 410 printf("\n"); | 499 printf("\n"); |
| 411 v8::String::Utf8Value stack_trace(try_catch->StackTrace()); | 500 v8::String::Utf8Value stack_trace(try_catch->StackTrace()); |
| 412 if (stack_trace.length() > 0) { | 501 if (stack_trace.length() > 0) { |
| 413 const char* stack_trace_string = ToCString(stack_trace); | 502 const char* stack_trace_string = ToCString(stack_trace); |
| 414 printf("%s\n", stack_trace_string); | 503 printf("%s\n", stack_trace_string); |
| 415 } | 504 } |
| 416 } | 505 } |
| 417 } | 506 } |
| OLD | NEW |