| Index: samples/shell.cc
|
| ===================================================================
|
| --- samples/shell.cc (revision 7267)
|
| +++ samples/shell.cc (working copy)
|
| @@ -33,7 +33,26 @@
|
| #include <stdio.h>
|
| #include <stdlib.h>
|
|
|
| +#include "../src/v8.h"
|
|
|
| +// TODO(isolates):
|
| +// o Either use V8 internal platform stuff for every platform or
|
| +// re-implement it.
|
| +// o Do not assume not WIN32 implies pthreads.
|
| +#ifndef WIN32
|
| +#include <pthread.h> // NOLINT
|
| +#include <unistd.h> // NOLINT
|
| +#endif
|
| +
|
| +static void ExitShell(int exit_code) {
|
| + // Use _exit instead of exit to avoid races between isolate
|
| + // threads and static destructors.
|
| + fflush(stdout);
|
| + fflush(stderr);
|
| + _exit(exit_code);
|
| +}
|
| +
|
| +v8::Persistent<v8::Context> CreateShellContext();
|
| void RunShell(v8::Handle<v8::Context> context);
|
| bool ExecuteString(v8::Handle<v8::String> source,
|
| v8::Handle<v8::Value> name,
|
| @@ -48,63 +67,193 @@
|
| void ReportException(v8::TryCatch* handler);
|
|
|
|
|
| +#ifndef WIN32
|
| +void* IsolateThreadEntry(void* arg);
|
| +#endif
|
| +
|
| +static bool last_run = true;
|
| +
|
| +class SourceGroup {
|
| + public:
|
| + SourceGroup() : argv_(NULL),
|
| + begin_offset_(0),
|
| + end_offset_(0),
|
| + next_semaphore_(NULL),
|
| + done_semaphore_(NULL) {
|
| +#ifndef WIN32
|
| + next_semaphore_ = v8::internal::OS::CreateSemaphore(0);
|
| + done_semaphore_ = v8::internal::OS::CreateSemaphore(0);
|
| + thread_ = 0;
|
| +#endif
|
| + }
|
| +
|
| + void Begin(char** argv, int offset) {
|
| + argv_ = const_cast<const char**>(argv);
|
| + begin_offset_ = offset;
|
| + }
|
| +
|
| + void End(int offset) { end_offset_ = offset; }
|
| +
|
| + void Execute() {
|
| + for (int i = begin_offset_; i < end_offset_; ++i) {
|
| + const char* arg = argv_[i];
|
| + if (strcmp(arg, "-e") == 0 && i + 1 < end_offset_) {
|
| + // Execute argument given to -e option directly.
|
| + v8::HandleScope handle_scope;
|
| + v8::Handle<v8::String> file_name = v8::String::New("unnamed");
|
| + v8::Handle<v8::String> source = v8::String::New(argv_[i + 1]);
|
| + if (!ExecuteString(source, file_name, false, true)) {
|
| + ExitShell(1);
|
| + return;
|
| + }
|
| + ++i;
|
| + } else if (arg[0] == '-') {
|
| + // Ignore other options. They have been parsed already.
|
| + } else {
|
| + // Use all other arguments as names of files to load and run.
|
| + v8::HandleScope handle_scope;
|
| + v8::Handle<v8::String> file_name = v8::String::New(arg);
|
| + v8::Handle<v8::String> source = ReadFile(arg);
|
| + if (source.IsEmpty()) {
|
| + printf("Error reading '%s'\n", arg);
|
| + }
|
| + if (!ExecuteString(source, file_name, false, true)) {
|
| + ExitShell(1);
|
| + return;
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| +#ifdef WIN32
|
| + void StartExecuteInThread() { ExecuteInThread(); }
|
| + void WaitForThread() {}
|
| +
|
| +#else
|
| + void StartExecuteInThread() {
|
| + if (thread_ == 0) {
|
| + pthread_attr_t attr;
|
| + // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
|
| + // which is not enough to parse the big literal expressions used in tests.
|
| + // The stack size should be at least StackGuard::kLimitSize + some
|
| + // OS-specific padding for thread startup code.
|
| + size_t stacksize = 2 << 20; // 2 Mb seems to be enough
|
| + pthread_attr_init(&attr);
|
| + pthread_attr_setstacksize(&attr, stacksize);
|
| + int error = pthread_create(&thread_, &attr, &IsolateThreadEntry, this);
|
| + if (error != 0) {
|
| + fprintf(stderr, "Error creating isolate thread.\n");
|
| + ExitShell(1);
|
| + }
|
| + }
|
| + next_semaphore_->Signal();
|
| + }
|
| +
|
| + void WaitForThread() {
|
| + if (thread_ == 0) return;
|
| + if (last_run) {
|
| + pthread_join(thread_, NULL);
|
| + thread_ = 0;
|
| + } else {
|
| + done_semaphore_->Wait();
|
| + }
|
| + }
|
| +#endif // WIN32
|
| +
|
| + private:
|
| + void ExecuteInThread() {
|
| + v8::Isolate* isolate = v8::Isolate::New();
|
| + do {
|
| + if (next_semaphore_ != NULL) next_semaphore_->Wait();
|
| + {
|
| + v8::Isolate::Scope iscope(isolate);
|
| + v8::HandleScope scope;
|
| + v8::Persistent<v8::Context> context = CreateShellContext();
|
| + {
|
| + v8::Context::Scope cscope(context);
|
| + Execute();
|
| + }
|
| + context.Dispose();
|
| + }
|
| + if (done_semaphore_ != NULL) done_semaphore_->Signal();
|
| + } while (!last_run);
|
| + isolate->Dispose();
|
| + }
|
| +
|
| + const char** argv_;
|
| + int begin_offset_;
|
| + int end_offset_;
|
| + v8::internal::Semaphore* next_semaphore_;
|
| + v8::internal::Semaphore* done_semaphore_;
|
| +#ifndef WIN32
|
| + pthread_t thread_;
|
| +#endif
|
| +
|
| + friend void* IsolateThreadEntry(void* arg);
|
| +};
|
| +
|
| +#ifndef WIN32
|
| +void* IsolateThreadEntry(void* arg) {
|
| + reinterpret_cast<SourceGroup*>(arg)->ExecuteInThread();
|
| + return NULL;
|
| +}
|
| +#endif
|
| +
|
| +
|
| +static SourceGroup* isolate_sources = NULL;
|
| +
|
| +
|
| int RunMain(int argc, char* argv[]) {
|
| + v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
|
| v8::HandleScope handle_scope;
|
| - // Create a template for the global object.
|
| - v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
|
| - // Bind the global 'print' function to the C++ Print callback.
|
| - global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
|
| - // Bind the global 'read' function to the C++ Read callback.
|
| - global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
|
| - // Bind the global 'load' function to the C++ Load callback.
|
| - global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
|
| - // Bind the 'quit' function
|
| - global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
|
| - // Bind the 'version' function
|
| - global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
|
| - // Create a new execution environment containing the built-in
|
| - // functions
|
| - v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
|
| + v8::Persistent<v8::Context> context = CreateShellContext();
|
| + // Enter the newly created execution environment.
|
| + context->Enter();
|
| if (context.IsEmpty()) {
|
| printf("Error creating context\n");
|
| return 1;
|
| }
|
|
|
| bool run_shell = (argc == 1);
|
| + int num_isolates = 1;
|
| for (int i = 1; i < argc; i++) {
|
| - // Enter the execution environment before evaluating any code.
|
| - v8::Context::Scope context_scope(context);
|
| - const char* str = argv[i];
|
| - if (strcmp(str, "--shell") == 0) {
|
| - run_shell = true;
|
| - } else if (strcmp(str, "-f") == 0) {
|
| - // Ignore any -f flags for compatibility with the other stand-
|
| - // alone JavaScript engines.
|
| - continue;
|
| - } else if (strncmp(str, "--", 2) == 0) {
|
| - printf("Warning: unknown flag %s.\nTry --help for options\n", str);
|
| - } else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
|
| - // Execute argument given to -e option directly
|
| - v8::HandleScope handle_scope;
|
| - v8::Handle<v8::String> file_name = v8::String::New("unnamed");
|
| - v8::Handle<v8::String> source = v8::String::New(argv[i + 1]);
|
| - if (!ExecuteString(source, file_name, false, true))
|
| - return 1;
|
| - i++;
|
| - } else {
|
| - // Use all other arguments as names of files to load and run.
|
| - v8::HandleScope handle_scope;
|
| - v8::Handle<v8::String> file_name = v8::String::New(str);
|
| - v8::Handle<v8::String> source = ReadFile(str);
|
| - if (source.IsEmpty()) {
|
| - printf("Error reading '%s'\n", str);
|
| - return 1;
|
| + if (strcmp(argv[i], "--isolate") == 0) ++num_isolates;
|
| + }
|
| + if (isolate_sources == NULL) {
|
| + isolate_sources = new SourceGroup[num_isolates];
|
| + SourceGroup* current = isolate_sources;
|
| + current->Begin(argv, 1);
|
| + for (int i = 1; i < argc; i++) {
|
| + const char* str = argv[i];
|
| + if (strcmp(str, "--isolate") == 0) {
|
| + current->End(i);
|
| + current++;
|
| + current->Begin(argv, i + 1);
|
| + } else if (strcmp(str, "--shell") == 0) {
|
| + run_shell = true;
|
| + } else if (strcmp(str, "-f") == 0) {
|
| + // Ignore any -f flags for compatibility with the other stand-
|
| + // alone JavaScript engines.
|
| + continue;
|
| + } else if (strncmp(str, "--", 2) == 0) {
|
| + printf("Warning: unknown flag %s.\nTry --help for options\n", str);
|
| }
|
| - if (!ExecuteString(source, file_name, false, true))
|
| - return 1;
|
| }
|
| + current->End(argc);
|
| }
|
| + for (int i = 1; i < num_isolates; ++i) {
|
| + isolate_sources[i].StartExecuteInThread();
|
| + }
|
| + isolate_sources[0].Execute();
|
| if (run_shell) RunShell(context);
|
| + for (int i = 1; i < num_isolates; ++i) {
|
| + isolate_sources[i].WaitForThread();
|
| + }
|
| + if (last_run) {
|
| + delete[] isolate_sources;
|
| + isolate_sources = NULL;
|
| + }
|
| + context->Exit();
|
| context.Dispose();
|
| return 0;
|
| }
|
| @@ -142,6 +291,7 @@
|
| printf("============ Stress %d/%d ============\n",
|
| i + 1, stress_runs);
|
| v8::Testing::PrepareStressRun(i);
|
| + last_run = (i == stress_runs - 1);
|
| result = RunMain(argc, argv);
|
| }
|
| printf("======== Full Deoptimization =======\n");
|
| @@ -160,6 +310,25 @@
|
| }
|
|
|
|
|
| +// Creates a new execution environment containing the built-in
|
| +// functions.
|
| +v8::Persistent<v8::Context> CreateShellContext() {
|
| + // Create a template for the global object.
|
| + v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
|
| + // Bind the global 'print' function to the C++ Print callback.
|
| + global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
|
| + // Bind the global 'read' function to the C++ Read callback.
|
| + global->Set(v8::String::New("read"), v8::FunctionTemplate::New(Read));
|
| + // Bind the global 'load' function to the C++ Load callback.
|
| + global->Set(v8::String::New("load"), v8::FunctionTemplate::New(Load));
|
| + // Bind the 'quit' function
|
| + global->Set(v8::String::New("quit"), v8::FunctionTemplate::New(Quit));
|
| + // Bind the 'version' function
|
| + global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
|
| + return v8::Context::New(NULL, global);
|
| +}
|
| +
|
| +
|
| // The callback that is invoked by v8 whenever the JavaScript 'print'
|
| // function is called. Prints its arguments on stdout separated by
|
| // spaces and ending with a newline.
|
| @@ -229,7 +398,7 @@
|
| // If not arguments are given args[0] will yield undefined which
|
| // converts to the integer value 0.
|
| int exit_code = args[0]->Int32Value();
|
| - exit(exit_code);
|
| + ExitShell(exit_code);
|
| return v8::Undefined();
|
| }
|
|
|
|
|