| Index: samples/shell.cc
|
| ===================================================================
|
| --- samples/shell.cc (revision 9006)
|
| +++ samples/shell.cc (working copy)
|
| @@ -26,39 +26,28 @@
|
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
| #include <v8.h>
|
| -#include <v8-testing.h>
|
| #include <assert.h>
|
| -#ifdef COMPRESS_STARTUP_DATA_BZ2
|
| -#include <bzlib.h>
|
| -#endif
|
| #include <fcntl.h>
|
| #include <string.h>
|
| #include <stdio.h>
|
| #include <stdlib.h>
|
|
|
| -// When building with V8 in a shared library we cannot use functions which
|
| -// is not explicitly a part of the public V8 API. This extensive use of
|
| -// #ifndef USING_V8_SHARED/#endif is a hack until we can resolve whether to
|
| -// still use the shell sample for testing or change to use the developer
|
| -// shell d8 TODO(1272).
|
| -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
|
| -#include "../src/v8.h"
|
| -#endif // USING_V8_SHARED
|
| -
|
| -#if !defined(_WIN32) && !defined(_WIN64)
|
| -#include <unistd.h> // NOLINT
|
| +#ifdef COMPRESS_STARTUP_DATA_BZ2
|
| +#error Using compressed startup data is not supported for this sample
|
| #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);
|
| -}
|
| +/**
|
| + * This sample program shows how to implement a simple javascript shell
|
| + * based on V8. This includes initializing V8 with command line options,
|
| + * creating global functions, compiling and executing strings.
|
| + *
|
| + * For a more sophisticated shell, consider using the debug shell D8.
|
| + */
|
|
|
| +
|
| v8::Persistent<v8::Context> CreateShellContext();
|
| void RunShell(v8::Handle<v8::Context> context);
|
| +int RunMain(int argc, char* argv[]);
|
| bool ExecuteString(v8::Handle<v8::String> source,
|
| v8::Handle<v8::Value> name,
|
| bool print_result,
|
| @@ -68,305 +57,28 @@
|
| v8::Handle<v8::Value> Load(const v8::Arguments& args);
|
| v8::Handle<v8::Value> Quit(const v8::Arguments& args);
|
| v8::Handle<v8::Value> Version(const v8::Arguments& args);
|
| -v8::Handle<v8::Value> Int8Array(const v8::Arguments& args);
|
| -v8::Handle<v8::Value> Uint8Array(const v8::Arguments& args);
|
| -v8::Handle<v8::Value> Int16Array(const v8::Arguments& args);
|
| -v8::Handle<v8::Value> Uint16Array(const v8::Arguments& args);
|
| -v8::Handle<v8::Value> Int32Array(const v8::Arguments& args);
|
| -v8::Handle<v8::Value> Uint32Array(const v8::Arguments& args);
|
| -v8::Handle<v8::Value> Float32Array(const v8::Arguments& args);
|
| -v8::Handle<v8::Value> Float64Array(const v8::Arguments& args);
|
| -v8::Handle<v8::Value> PixelArray(const v8::Arguments& args);
|
| v8::Handle<v8::String> ReadFile(const char* name);
|
| void ReportException(v8::TryCatch* handler);
|
|
|
|
|
| -static bool last_run = true;
|
| +static bool run_shell;
|
|
|
| -class SourceGroup {
|
| - public:
|
| - SourceGroup() :
|
| -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
|
| - next_semaphore_(v8::internal::OS::CreateSemaphore(0)),
|
| - done_semaphore_(v8::internal::OS::CreateSemaphore(0)),
|
| - thread_(NULL),
|
| -#endif // USING_V8_SHARED
|
| - argv_(NULL),
|
| - begin_offset_(0),
|
| - end_offset_(0) { }
|
|
|
| -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
|
| - ~SourceGroup() {
|
| - delete next_semaphore_;
|
| - delete done_semaphore_;
|
| - }
|
| -#endif // USING_V8_SHARED
|
| -
|
| - 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);
|
| - continue;
|
| - }
|
| - if (!ExecuteString(source, file_name, false, true)) {
|
| - ExitShell(1);
|
| - return;
|
| - }
|
| - }
|
| - }
|
| - }
|
| -
|
| -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
|
| - void StartExecuteInThread() {
|
| - if (thread_ == NULL) {
|
| - thread_ = new IsolateThread(this);
|
| - thread_->Start();
|
| - }
|
| - next_semaphore_->Signal();
|
| - }
|
| -
|
| - void WaitForThread() {
|
| - if (thread_ == NULL) return;
|
| - if (last_run) {
|
| - thread_->Join();
|
| - thread_ = NULL;
|
| - } else {
|
| - done_semaphore_->Wait();
|
| - }
|
| - }
|
| -#endif // USING_V8_SHARED
|
| -
|
| - private:
|
| -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
|
| - static v8::internal::Thread::Options GetThreadOptions() {
|
| - v8::internal::Thread::Options options;
|
| - options.name = "IsolateThread";
|
| - // 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.
|
| - options.stack_size = 2 << 20; // 2 Mb seems to be enough
|
| - return options;
|
| - }
|
| -
|
| - class IsolateThread : public v8::internal::Thread {
|
| - public:
|
| - explicit IsolateThread(SourceGroup* group)
|
| - : v8::internal::Thread(GetThreadOptions()), group_(group) {}
|
| -
|
| - virtual void Run() {
|
| - group_->ExecuteInThread();
|
| - }
|
| -
|
| - private:
|
| - SourceGroup* group_;
|
| - };
|
| -
|
| - 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();
|
| - }
|
| -
|
| - v8::internal::Semaphore* next_semaphore_;
|
| - v8::internal::Semaphore* done_semaphore_;
|
| - v8::internal::Thread* thread_;
|
| -#endif // USING_V8_SHARED
|
| -
|
| - const char** argv_;
|
| - int begin_offset_;
|
| - int end_offset_;
|
| -};
|
| -
|
| -
|
| -static SourceGroup* isolate_sources = NULL;
|
| -
|
| -
|
| -#ifdef COMPRESS_STARTUP_DATA_BZ2
|
| -class BZip2Decompressor : public v8::StartupDataDecompressor {
|
| - public:
|
| - virtual ~BZip2Decompressor() { }
|
| -
|
| - protected:
|
| - virtual int DecompressData(char* raw_data,
|
| - int* raw_data_size,
|
| - const char* compressed_data,
|
| - int compressed_data_size) {
|
| - ASSERT_EQ(v8::StartupData::kBZip2,
|
| - v8::V8::GetCompressedStartupDataAlgorithm());
|
| - unsigned int decompressed_size = *raw_data_size;
|
| - int result =
|
| - BZ2_bzBuffToBuffDecompress(raw_data,
|
| - &decompressed_size,
|
| - const_cast<char*>(compressed_data),
|
| - compressed_data_size,
|
| - 0, 1);
|
| - if (result == BZ_OK) {
|
| - *raw_data_size = decompressed_size;
|
| - }
|
| - return result;
|
| - }
|
| -};
|
| -#endif
|
| -
|
| -
|
| -int RunMain(int argc, char* argv[]) {
|
| +int main(int argc, char* argv[]) {
|
| v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
|
| + run_shell = (argc == 1);
|
| v8::HandleScope handle_scope;
|
| 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++) {
|
| - if (strcmp(argv[i], "--isolate") == 0) {
|
| -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
|
| - ++num_isolates;
|
| -#else // USING_V8_SHARED
|
| - printf("Error: --isolate not supported when linked with shared "
|
| - "library\n");
|
| - ExitShell(1);
|
| -#endif // USING_V8_SHARED
|
| - }
|
| - }
|
| - 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);
|
| - }
|
| - }
|
| - current->End(argc);
|
| - }
|
| -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
|
| - for (int i = 1; i < num_isolates; ++i) {
|
| - isolate_sources[i].StartExecuteInThread();
|
| - }
|
| -#endif // USING_V8_SHARED
|
| - isolate_sources[0].Execute();
|
| + context->Enter();
|
| + int result = RunMain(argc, argv);
|
| if (run_shell) RunShell(context);
|
| -#if !(defined(USING_V8_SHARED) || defined(V8_SHARED))
|
| - for (int i = 1; i < num_isolates; ++i) {
|
| - isolate_sources[i].WaitForThread();
|
| - }
|
| -#endif // USING_V8_SHARED
|
| - if (last_run) {
|
| - delete[] isolate_sources;
|
| - isolate_sources = NULL;
|
| - }
|
| context->Exit();
|
| context.Dispose();
|
| - return 0;
|
| -}
|
| -
|
| -
|
| -int main(int argc, char* argv[]) {
|
| - // Figure out if we're requested to stress the optimization
|
| - // infrastructure by running tests multiple times and forcing
|
| - // optimization in the last run.
|
| - bool FLAG_stress_opt = false;
|
| - bool FLAG_stress_deopt = false;
|
| - for (int i = 0; i < argc; i++) {
|
| - if (strcmp(argv[i], "--stress-opt") == 0) {
|
| - FLAG_stress_opt = true;
|
| - argv[i] = NULL;
|
| - } else if (strcmp(argv[i], "--stress-deopt") == 0) {
|
| - FLAG_stress_deopt = true;
|
| - argv[i] = NULL;
|
| - } else if (strcmp(argv[i], "--noalways-opt") == 0) {
|
| - // No support for stressing if we can't use --always-opt.
|
| - FLAG_stress_opt = false;
|
| - FLAG_stress_deopt = false;
|
| - break;
|
| - }
|
| - }
|
| -
|
| -#ifdef COMPRESS_STARTUP_DATA_BZ2
|
| - BZip2Decompressor startup_data_decompressor;
|
| - int bz2_result = startup_data_decompressor.Decompress();
|
| - if (bz2_result != BZ_OK) {
|
| - fprintf(stderr, "bzip error code: %d\n", bz2_result);
|
| - exit(1);
|
| - }
|
| -#endif
|
| -
|
| - v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
|
| - int result = 0;
|
| - if (FLAG_stress_opt || FLAG_stress_deopt) {
|
| - v8::Testing::SetStressRunType(FLAG_stress_opt
|
| - ? v8::Testing::kStressTypeOpt
|
| - : v8::Testing::kStressTypeDeopt);
|
| - int stress_runs = v8::Testing::GetStressRuns();
|
| - for (int i = 0; i < stress_runs && result == 0; i++) {
|
| - 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");
|
| - v8::Testing::DeoptimizeAll();
|
| - } else {
|
| - result = RunMain(argc, argv);
|
| - }
|
| v8::V8::Dispose();
|
| -
|
| return result;
|
| }
|
|
|
| @@ -393,26 +105,6 @@
|
| // Bind the 'version' function
|
| global->Set(v8::String::New("version"), v8::FunctionTemplate::New(Version));
|
|
|
| - // Bind the handlers for external arrays.
|
| - global->Set(v8::String::New("Int8Array"),
|
| - v8::FunctionTemplate::New(Int8Array));
|
| - global->Set(v8::String::New("Uint8Array"),
|
| - v8::FunctionTemplate::New(Uint8Array));
|
| - global->Set(v8::String::New("Int16Array"),
|
| - v8::FunctionTemplate::New(Int16Array));
|
| - global->Set(v8::String::New("Uint16Array"),
|
| - v8::FunctionTemplate::New(Uint16Array));
|
| - global->Set(v8::String::New("Int32Array"),
|
| - v8::FunctionTemplate::New(Int32Array));
|
| - global->Set(v8::String::New("Uint32Array"),
|
| - v8::FunctionTemplate::New(Uint32Array));
|
| - global->Set(v8::String::New("Float32Array"),
|
| - v8::FunctionTemplate::New(Float32Array));
|
| - global->Set(v8::String::New("Float64Array"),
|
| - v8::FunctionTemplate::New(Float64Array));
|
| - global->Set(v8::String::New("PixelArray"),
|
| - v8::FunctionTemplate::New(PixelArray));
|
| -
|
| return v8::Context::New(NULL, global);
|
| }
|
|
|
| @@ -486,7 +178,9 @@
|
| // If not arguments are given args[0] will yield undefined which
|
| // converts to the integer value 0.
|
| int exit_code = args[0]->Int32Value();
|
| - ExitShell(exit_code);
|
| + fflush(stdout);
|
| + fflush(stderr);
|
| + exit(exit_code);
|
| return v8::Undefined();
|
| }
|
|
|
| @@ -496,113 +190,6 @@
|
| }
|
|
|
|
|
| -void ExternalArrayWeakCallback(v8::Persistent<v8::Value> object, void* data) {
|
| - free(data);
|
| - object.Dispose();
|
| -}
|
| -
|
| -
|
| -v8::Handle<v8::Value> CreateExternalArray(const v8::Arguments& args,
|
| - v8::ExternalArrayType type,
|
| - size_t element_size) {
|
| - assert(element_size == 1 ||
|
| - element_size == 2 ||
|
| - element_size == 4 ||
|
| - element_size == 8);
|
| - if (args.Length() != 1) {
|
| - return v8::ThrowException(
|
| - v8::String::New("Array constructor needs one parameter."));
|
| - }
|
| - static const int kMaxLength = 0x3fffffff;
|
| - size_t length = 0;
|
| - if (args[0]->IsUint32()) {
|
| - length = args[0]->Uint32Value();
|
| - } else if (args[0]->IsNumber()) {
|
| - double raw_length = args[0]->NumberValue();
|
| - if (raw_length < 0) {
|
| - return v8::ThrowException(
|
| - v8::String::New("Array length must not be negative."));
|
| - }
|
| - if (raw_length > kMaxLength) {
|
| - return v8::ThrowException(
|
| - v8::String::New("Array length exceeds maximum length."));
|
| - }
|
| - length = static_cast<size_t>(raw_length);
|
| - } else {
|
| - return v8::ThrowException(
|
| - v8::String::New("Array length must be a number."));
|
| - }
|
| - if (length > static_cast<size_t>(kMaxLength)) {
|
| - return v8::ThrowException(
|
| - v8::String::New("Array length exceeds maximum length."));
|
| - }
|
| - void* data = calloc(length, element_size);
|
| - if (data == NULL) {
|
| - return v8::ThrowException(v8::String::New("Memory allocation failed."));
|
| - }
|
| - v8::Handle<v8::Object> array = v8::Object::New();
|
| - v8::Persistent<v8::Object> persistent_array =
|
| - v8::Persistent<v8::Object>::New(array);
|
| - persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
|
| - persistent_array.MarkIndependent();
|
| - array->SetIndexedPropertiesToExternalArrayData(data, type, length);
|
| - array->Set(v8::String::New("length"), v8::Int32::New(length),
|
| - v8::ReadOnly);
|
| - array->Set(v8::String::New("BYTES_PER_ELEMENT"),
|
| - v8::Int32::New(element_size));
|
| - return array;
|
| -}
|
| -
|
| -
|
| -v8::Handle<v8::Value> Int8Array(const v8::Arguments& args) {
|
| - return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
|
| -}
|
| -
|
| -
|
| -v8::Handle<v8::Value> Uint8Array(const v8::Arguments& args) {
|
| - return CreateExternalArray(args, v8::kExternalUnsignedByteArray,
|
| - sizeof(uint8_t));
|
| -}
|
| -
|
| -
|
| -v8::Handle<v8::Value> Int16Array(const v8::Arguments& args) {
|
| - return CreateExternalArray(args, v8::kExternalShortArray, sizeof(int16_t));
|
| -}
|
| -
|
| -
|
| -v8::Handle<v8::Value> Uint16Array(const v8::Arguments& args) {
|
| - return CreateExternalArray(args, v8::kExternalUnsignedShortArray,
|
| - sizeof(uint16_t));
|
| -}
|
| -
|
| -v8::Handle<v8::Value> Int32Array(const v8::Arguments& args) {
|
| - return CreateExternalArray(args, v8::kExternalIntArray, sizeof(int32_t));
|
| -}
|
| -
|
| -
|
| -v8::Handle<v8::Value> Uint32Array(const v8::Arguments& args) {
|
| - return CreateExternalArray(args, v8::kExternalUnsignedIntArray,
|
| - sizeof(uint32_t));
|
| -}
|
| -
|
| -
|
| -v8::Handle<v8::Value> Float32Array(const v8::Arguments& args) {
|
| - return CreateExternalArray(args, v8::kExternalFloatArray,
|
| - sizeof(float)); // NOLINT
|
| -}
|
| -
|
| -
|
| -v8::Handle<v8::Value> Float64Array(const v8::Arguments& args) {
|
| - return CreateExternalArray(args, v8::kExternalDoubleArray,
|
| - sizeof(double)); // NOLINT
|
| -}
|
| -
|
| -
|
| -v8::Handle<v8::Value> PixelArray(const v8::Arguments& args) {
|
| - return CreateExternalArray(args, v8::kExternalPixelArray, sizeof(uint8_t));
|
| -}
|
| -
|
| -
|
| // Reads a file into a v8 string.
|
| v8::Handle<v8::String> ReadFile(const char* name) {
|
| FILE* file = fopen(name, "rb");
|
| @@ -625,9 +212,41 @@
|
| }
|
|
|
|
|
| +// Process remaining command line arguments and execute files
|
| +int RunMain(int argc, char* argv[]) {
|
| + for (int i = 1; i < argc; i++) {
|
| + 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::Handle<v8::String> file_name = v8::String::New("unnamed");
|
| + v8::Handle<v8::String> source = v8::String::New(argv[++i]);
|
| + if (!ExecuteString(source, file_name, false, true)) return 1;
|
| + } else {
|
| + // Use all other arguments as names of files to load and run.
|
| + 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);
|
| + continue;
|
| + }
|
| + if (!ExecuteString(source, file_name, false, true)) return 1;
|
| + }
|
| + }
|
| + return 0;
|
| +}
|
| +
|
| +
|
| // The read-eval-execute loop of the shell.
|
| void RunShell(v8::Handle<v8::Context> context) {
|
| - printf("V8 version %s\n", v8::V8::GetVersion());
|
| + printf("V8 version %s [sample shell]\n", v8::V8::GetVersion());
|
| static const int kBufferSize = 256;
|
| // Enter the execution environment before evaluating any code.
|
| v8::Context::Scope context_scope(context);
|
|
|