Upgrade to V8 3.4

Merge 3.4.14.35

Simple merge required updates to makefiles only.

Bug: 568872
Change-Id: I403a38452c547e06fcfa951c12eca12a1bc40978
diff --git a/src/d8.cc b/src/d8.cc
index f1068cb..5fd9d27 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1,4 +1,4 @@
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -26,27 +26,49 @@
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 
-#include <stdlib.h>
-#include <errno.h>
+#ifdef V8_SHARED
+#define USING_V8_SHARED
+#endif
 
-#include "v8.h"
+#ifdef COMPRESS_STARTUP_DATA_BZ2
+#include <bzlib.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef USING_V8_SHARED
+#include <assert.h>
+#include "../include/v8-testing.h"
+#endif  // USING_V8_SHARED
 
 #include "d8.h"
+
+#ifndef USING_V8_SHARED
+#include "api.h"
+#include "checks.h"
 #include "d8-debug.h"
 #include "debug.h"
-#include "api.h"
 #include "natives.h"
 #include "platform.h"
+#include "v8.h"
+#endif  // USING_V8_SHARED
 
+#if !defined(_WIN32) && !defined(_WIN64)
+#include <unistd.h>  // NOLINT
+#endif
+
+#ifdef USING_V8_SHARED
+#define ASSERT(condition) assert(condition)
+#endif  // USING_V8_SHARED
 
 namespace v8 {
 
 
-const char* Shell::kHistoryFileName = ".d8_history";
-const char* Shell::kPrompt = "d8> ";
-
-
+#ifndef USING_V8_SHARED
 LineEditor *LineEditor::first_ = NULL;
+const char* Shell::kHistoryFileName = ".d8_history";
 
 
 LineEditor::LineEditor(Type type, const char* name)
@@ -92,15 +114,22 @@
 i::OS::MemoryMappedFile* Shell::counters_file_ = NULL;
 CounterCollection Shell::local_counters_;
 CounterCollection* Shell::counters_ = &local_counters_;
+i::Mutex* Shell::context_mutex_(i::OS::CreateMutex());
 Persistent<Context> Shell::utility_context_;
+#endif  // USING_V8_SHARED
+
 Persistent<Context> Shell::evaluation_context_;
+ShellOptions Shell::options;
+const char* Shell::kPrompt = "d8> ";
 
 
+#ifndef USING_V8_SHARED
 bool CounterMap::Match(void* key1, void* key2) {
   const char* name1 = reinterpret_cast<const char*>(key1);
   const char* name2 = reinterpret_cast<const char*>(key2);
   return strcmp(name1, name2) == 0;
 }
+#endif  // USING_V8_SHARED
 
 
 // Converts a V8 value to a C string.
@@ -114,16 +143,22 @@
                           Handle<Value> name,
                           bool print_result,
                           bool report_exceptions) {
+#ifndef USING_V8_SHARED
+  bool FLAG_debugger = i::FLAG_debugger;
+#else
+  bool FLAG_debugger = false;
+#endif  // USING_V8_SHARED
   HandleScope handle_scope;
   TryCatch try_catch;
-  if (i::FLAG_debugger) {
+  options.script_executed = true;
+  if (FLAG_debugger) {
     // When debugging make exceptions appear to be uncaught.
     try_catch.SetVerbose(true);
   }
   Handle<Script> script = Script::Compile(source, name);
   if (script.IsEmpty()) {
     // Print errors that happened during compilation.
-    if (report_exceptions && !i::FLAG_debugger)
+    if (report_exceptions && !FLAG_debugger)
       ReportException(&try_catch);
     return false;
   } else {
@@ -131,7 +166,7 @@
     if (result.IsEmpty()) {
       ASSERT(try_catch.HasCaught());
       // Print errors that happened during execution.
-      if (report_exceptions && !i::FLAG_debugger)
+      if (report_exceptions && !FLAG_debugger)
         ReportException(&try_catch);
       return false;
     } else {
@@ -152,6 +187,7 @@
 Handle<Value> Shell::Print(const Arguments& args) {
   Handle<Value> val = Write(args);
   printf("\n");
+  fflush(stdout);
   return val;
 }
 
@@ -187,15 +223,20 @@
 
 
 Handle<Value> Shell::ReadLine(const Arguments& args) {
-  i::SmartPointer<char> line(i::ReadLine(""));
-  if (*line == NULL) {
-    return Null();
-  }
-  size_t len = strlen(*line);
-  if (len > 0 && line[len - 1] == '\n') {
-    --len;
-  }
-  return String::New(*line, len);
+  static const int kBufferSize = 256;
+  char buffer[kBufferSize];
+  Handle<String> accumulator = String::New("");
+  bool linebreak;
+  int length;
+  do {  // Repeat if the line ends with an escape '\'.
+    // fgets got an error. Just give up.
+    if (fgets(buffer, kBufferSize, stdin) == NULL) return Null();
+    length = strlen(buffer);
+    linebreak = (length > 1 && buffer[length-2] == '\\');
+    if (linebreak) buffer[length-2] = '\n';
+    accumulator = String::Concat(accumulator, String::New(buffer, length-1));
+  } while (linebreak);
+  return accumulator;
 }
 
 
@@ -218,6 +259,107 @@
 }
 
 
+Handle<Value> Shell::CreateExternalArray(const Arguments& args,
+                                         ExternalArrayType type,
+                                         size_t element_size) {
+  ASSERT(element_size == 1 || element_size == 2 || element_size == 4 ||
+         element_size == 8);
+  if (args.Length() != 1) {
+    return ThrowException(
+        String::New("Array constructor needs one parameter."));
+  }
+  static const int kMaxLength = 0x3fffffff;
+#ifndef USING_V8_SHARED
+  ASSERT(kMaxLength == i::ExternalArray::kMaxLength);
+#endif  // USING_V8_SHARED
+  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 ThrowException(String::New("Array length must not be negative."));
+    }
+    if (raw_length > kMaxLength) {
+      return ThrowException(
+          String::New("Array length exceeds maximum length."));
+    }
+    length = static_cast<size_t>(raw_length);
+  } else {
+    return ThrowException(String::New("Array length must be a number."));
+  }
+  if (length > static_cast<size_t>(kMaxLength)) {
+    return ThrowException(String::New("Array length exceeds maximum length."));
+  }
+  void* data = calloc(length, element_size);
+  if (data == NULL) {
+    return ThrowException(String::New("Memory allocation failed."));
+  }
+  Handle<Object> array = Object::New();
+  Persistent<Object> persistent_array = Persistent<Object>::New(array);
+  persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
+  persistent_array.MarkIndependent();
+  array->SetIndexedPropertiesToExternalArrayData(data, type, length);
+  array->Set(String::New("length"), Int32::New(length), ReadOnly);
+  array->Set(String::New("BYTES_PER_ELEMENT"), Int32::New(element_size));
+  return array;
+}
+
+
+void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
+  free(data);
+  object.Dispose();
+}
+
+
+Handle<Value> Shell::Int8Array(const Arguments& args) {
+  return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
+}
+
+
+Handle<Value> Shell::Uint8Array(const Arguments& args) {
+  return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t));
+}
+
+
+Handle<Value> Shell::Int16Array(const Arguments& args) {
+  return CreateExternalArray(args, kExternalShortArray, sizeof(int16_t));
+}
+
+
+Handle<Value> Shell::Uint16Array(const Arguments& args) {
+  return CreateExternalArray(args, kExternalUnsignedShortArray,
+                             sizeof(uint16_t));
+}
+
+
+Handle<Value> Shell::Int32Array(const Arguments& args) {
+  return CreateExternalArray(args, kExternalIntArray, sizeof(int32_t));
+}
+
+
+Handle<Value> Shell::Uint32Array(const Arguments& args) {
+  return CreateExternalArray(args, kExternalUnsignedIntArray, sizeof(uint32_t));
+}
+
+
+Handle<Value> Shell::Float32Array(const Arguments& args) {
+  return CreateExternalArray(args, kExternalFloatArray,
+                             sizeof(float));  // NOLINT
+}
+
+
+Handle<Value> Shell::Float64Array(const Arguments& args) {
+  return CreateExternalArray(args, kExternalDoubleArray,
+                             sizeof(double));  // NOLINT
+}
+
+
+Handle<Value> Shell::PixelArray(const Arguments& args) {
+  return CreateExternalArray(args, kExternalPixelArray, sizeof(uint8_t));
+}
+
+
 Handle<Value> Shell::Yield(const Arguments& args) {
   v8::Unlocker unlocker;
   return Undefined();
@@ -226,7 +368,9 @@
 
 Handle<Value> Shell::Quit(const Arguments& args) {
   int exit_code = args[0]->Int32Value();
+#ifndef USING_V8_SHARED
   OnExit();
+#endif  // USING_V8_SHARED
   exit(exit_code);
   return Undefined();
 }
@@ -275,6 +419,7 @@
 }
 
 
+#ifndef USING_V8_SHARED
 Handle<Array> Shell::GetCompletions(Handle<String> text, Handle<String> full) {
   HandleScope handle_scope;
   Context::Scope context_scope(utility_context_);
@@ -308,9 +453,11 @@
   Handle<Value> val = Handle<Function>::Cast(fun)->Call(global, kArgc, argv);
   return val;
 }
-#endif
+#endif  // ENABLE_DEBUGGER_SUPPORT
+#endif  // USING_V8_SHARED
 
 
+#ifndef USING_V8_SHARED
 int32_t* Counter::Bind(const char* name, bool is_histogram) {
   int i;
   for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
@@ -342,8 +489,8 @@
 
 
 void Shell::MapCounters(const char* name) {
-  counters_file_ = i::OS::MemoryMappedFile::create(name,
-    sizeof(CounterCollection), &local_counters_);
+  counters_file_ = i::OS::MemoryMappedFile::create(
+      name, sizeof(CounterCollection), &local_counters_);
   void* memory = (counters_file_ == NULL) ?
       NULL : counters_file_->memory();
   if (memory == NULL) {
@@ -409,56 +556,15 @@
 }
 
 
-void Shell::Initialize() {
-  Shell::counter_map_ = new CounterMap();
-  // Set up counters
-  if (i::StrLength(i::FLAG_map_counters) != 0)
-    MapCounters(i::FLAG_map_counters);
-  if (i::FLAG_dump_counters) {
-    V8::SetCounterFunction(LookupCounter);
-    V8::SetCreateHistogramFunction(CreateHistogram);
-    V8::SetAddHistogramSampleFunction(AddHistogramSample);
-  }
-
-  // Initialize the global objects
+void Shell::InstallUtilityScript() {
+  Locker lock;
   HandleScope scope;
-  Handle<ObjectTemplate> global_template = ObjectTemplate::New();
-  global_template->Set(String::New("print"), FunctionTemplate::New(Print));
-  global_template->Set(String::New("write"), FunctionTemplate::New(Write));
-  global_template->Set(String::New("read"), FunctionTemplate::New(Read));
-  global_template->Set(String::New("readline"),
-                       FunctionTemplate::New(ReadLine));
-  global_template->Set(String::New("load"), FunctionTemplate::New(Load));
-  global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
-  global_template->Set(String::New("version"), FunctionTemplate::New(Version));
-
-#ifdef LIVE_OBJECT_LIST
-  global_template->Set(String::New("lol_is_enabled"), Boolean::New(true));
-#else
-  global_template->Set(String::New("lol_is_enabled"), Boolean::New(false));
-#endif
-
-  Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
-  AddOSMethods(os_templ);
-  global_template->Set(String::New("os"), os_templ);
-
-  utility_context_ = Context::New(NULL, global_template);
+  // If we use the utility context, we have to set the security tokens so that
+  // utility, evaluation and debug context can all access each other.
   utility_context_->SetSecurityToken(Undefined());
+  evaluation_context_->SetSecurityToken(Undefined());
   Context::Scope utility_scope(utility_context_);
 
-  i::JSArguments js_args = i::FLAG_js_arguments;
-  i::Handle<i::FixedArray> arguments_array =
-      FACTORY->NewFixedArray(js_args.argc());
-  for (int j = 0; j < js_args.argc(); j++) {
-    i::Handle<i::String> arg =
-        FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
-    arguments_array->set(j, *arg);
-  }
-  i::Handle<i::JSArray> arguments_jsarray =
-      FACTORY->NewJSArrayWithElements(arguments_array);
-  global_template->Set(String::New("arguments"),
-                       Utils::ToLocal(arguments_jsarray));
-
 #ifdef ENABLE_DEBUGGER_SUPPORT
   // Install the debugger object in the utility scope
   i::Debug* debug = i::Isolate::Current()->debug();
@@ -467,21 +573,21 @@
       = i::Handle<i::JSObject>(debug->debug_context()->global());
   utility_context_->Global()->Set(String::New("$debug"),
                                   Utils::ToLocal(js_debug));
-#endif
+  debug->debug_context()->set_security_token(HEAP->undefined_value());
+#endif  // ENABLE_DEBUGGER_SUPPORT
 
   // Run the d8 shell utility script in the utility context
   int source_index = i::NativesCollection<i::D8>::GetIndex("d8");
-  i::Vector<const char> shell_source
-      = i::NativesCollection<i::D8>::GetScriptSource(source_index);
-  i::Vector<const char> shell_source_name
-      = i::NativesCollection<i::D8>::GetScriptName(source_index);
+  i::Vector<const char> shell_source =
+      i::NativesCollection<i::D8>::GetRawScriptSource(source_index);
+  i::Vector<const char> shell_source_name =
+      i::NativesCollection<i::D8>::GetScriptName(source_index);
   Handle<String> source = String::New(shell_source.start(),
-                                      shell_source.length());
+      shell_source.length());
   Handle<String> name = String::New(shell_source_name.start(),
-                                    shell_source_name.length());
+      shell_source_name.length());
   Handle<Script> script = Script::Compile(source, name);
   script->Run();
-
   // Mark the d8 shell script as native to avoid it showing up as normal source
   // in the debugger.
   i::Handle<i::Object> compiled_script = Utils::OpenHandle(*script);
@@ -492,53 +598,189 @@
           i::SharedFunctionInfo::cast(*compiled_script)->script()));
   script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
 
-  // Create the evaluation context
-  evaluation_context_ = Context::New(NULL, global_template);
-  evaluation_context_->SetSecurityToken(Undefined());
-
 #ifdef ENABLE_DEBUGGER_SUPPORT
-  // Set the security token of the debug context to allow access.
-  debug->debug_context()->set_security_token(HEAP->undefined_value());
-
-  // Start the debugger agent if requested.
-  if (i::FLAG_debugger_agent) {
-    v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
-  }
-
   // Start the in-process debugger if requested.
   if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
     v8::Debug::SetDebugEventListener(HandleDebugEvent);
   }
+#endif  // ENABLE_DEBUGGER_SUPPORT
+}
+#endif  // USING_V8_SHARED
+
+
+#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
+
+Handle<ObjectTemplate> Shell::CreateGlobalTemplate() {
+  Handle<ObjectTemplate> global_template = ObjectTemplate::New();
+  global_template->Set(String::New("print"), FunctionTemplate::New(Print));
+  global_template->Set(String::New("write"), FunctionTemplate::New(Write));
+  global_template->Set(String::New("read"), FunctionTemplate::New(Read));
+  global_template->Set(String::New("readline"),
+                       FunctionTemplate::New(ReadLine));
+  global_template->Set(String::New("load"), FunctionTemplate::New(Load));
+  global_template->Set(String::New("quit"), FunctionTemplate::New(Quit));
+  global_template->Set(String::New("version"), FunctionTemplate::New(Version));
+
+  // Bind the handlers for external arrays.
+  global_template->Set(String::New("Int8Array"),
+                       FunctionTemplate::New(Int8Array));
+  global_template->Set(String::New("Uint8Array"),
+                       FunctionTemplate::New(Uint8Array));
+  global_template->Set(String::New("Int16Array"),
+                       FunctionTemplate::New(Int16Array));
+  global_template->Set(String::New("Uint16Array"),
+                       FunctionTemplate::New(Uint16Array));
+  global_template->Set(String::New("Int32Array"),
+                       FunctionTemplate::New(Int32Array));
+  global_template->Set(String::New("Uint32Array"),
+                       FunctionTemplate::New(Uint32Array));
+  global_template->Set(String::New("Float32Array"),
+                       FunctionTemplate::New(Float32Array));
+  global_template->Set(String::New("Float64Array"),
+                       FunctionTemplate::New(Float64Array));
+  global_template->Set(String::New("PixelArray"),
+                       FunctionTemplate::New(PixelArray));
+
+#ifdef LIVE_OBJECT_LIST
+  global_template->Set(String::New("lol_is_enabled"), Boolean::New(true));
+#else
+  global_template->Set(String::New("lol_is_enabled"), Boolean::New(false));
+#endif
+
+#ifndef USING_V8_SHARED
+  Handle<ObjectTemplate> os_templ = ObjectTemplate::New();
+  AddOSMethods(os_templ);
+  global_template->Set(String::New("os"), os_templ);
+#endif  // USING_V8_SHARED
+
+  return global_template;
 }
 
 
+void Shell::Initialize() {
+#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
+
+#ifndef USING_V8_SHARED
+  Shell::counter_map_ = new CounterMap();
+  // Set up counters
+  if (i::StrLength(i::FLAG_map_counters) != 0)
+    MapCounters(i::FLAG_map_counters);
+  if (i::FLAG_dump_counters) {
+    V8::SetCounterFunction(LookupCounter);
+    V8::SetCreateHistogramFunction(CreateHistogram);
+    V8::SetAddHistogramSampleFunction(AddHistogramSample);
+  }
+#endif  // USING_V8_SHARED
+  if (options.test_shell) return;
+
+#ifndef USING_V8_SHARED
+  Locker lock;
+  HandleScope scope;
+  Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
+  utility_context_ = Context::New(NULL, global_template);
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // Start the debugger agent if requested.
+  if (i::FLAG_debugger_agent) {
+    v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
+  }
+#endif  // ENABLE_DEBUGGER_SUPPORT
+#endif  // USING_V8_SHARED
+}
+
+
+Persistent<Context> Shell::CreateEvaluationContext() {
+#ifndef USING_V8_SHARED
+  // This needs to be a critical section since this is not thread-safe
+  i::ScopedLock lock(context_mutex_);
+#endif  // USING_V8_SHARED
+  // Initialize the global objects
+  Handle<ObjectTemplate> global_template = CreateGlobalTemplate();
+  Persistent<Context> context = Context::New(NULL, global_template);
+  Context::Scope scope(context);
+
+#ifndef USING_V8_SHARED
+  i::JSArguments js_args = i::FLAG_js_arguments;
+  i::Handle<i::FixedArray> arguments_array =
+      FACTORY->NewFixedArray(js_args.argc());
+  for (int j = 0; j < js_args.argc(); j++) {
+    i::Handle<i::String> arg =
+        FACTORY->NewStringFromUtf8(i::CStrVector(js_args[j]));
+    arguments_array->set(j, *arg);
+  }
+  i::Handle<i::JSArray> arguments_jsarray =
+      FACTORY->NewJSArrayWithElements(arguments_array);
+  context->Global()->Set(String::New("arguments"),
+                         Utils::ToLocal(arguments_jsarray));
+#endif  // USING_V8_SHARED
+  return context;
+}
+
+
+#ifndef USING_V8_SHARED
 void Shell::OnExit() {
   if (i::FLAG_dump_counters) {
-    ::printf("+----------------------------------------+-------------+\n");
-    ::printf("| Name                                   | Value       |\n");
-    ::printf("+----------------------------------------+-------------+\n");
+    printf("+----------------------------------------+-------------+\n");
+    printf("| Name                                   | Value       |\n");
+    printf("+----------------------------------------+-------------+\n");
     for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
       Counter* counter = i.CurrentValue();
       if (counter->is_histogram()) {
-        ::printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
-        ::printf("| t:%-36s | %11i |\n",
-                 i.CurrentKey(),
-                 counter->sample_total());
+        printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
+        printf("| t:%-36s | %11i |\n", i.CurrentKey(), counter->sample_total());
       } else {
-        ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
+        printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
       }
     }
-    ::printf("+----------------------------------------+-------------+\n");
+    printf("+----------------------------------------+-------------+\n");
   }
   if (counters_file_ != NULL)
     delete counters_file_;
 }
+#endif  // USING_V8_SHARED
 
 
 static char* ReadChars(const char* name, int* size_out) {
-  v8::Unlocker unlocker;  // Release the V8 lock while reading files.
+  // Release the V8 lock while reading files.
+  v8::Unlocker unlocker(Isolate::GetCurrent());
+#ifndef USING_V8_SHARED
   FILE* file = i::OS::FOpen(name, "rb");
+#else
+  // TODO(yangguo@chromium.org): reading from a directory hangs!
+  FILE* file = fopen(name, "rb");
+#endif  // USING_V8_SHARED
   if (file == NULL) return NULL;
 
   fseek(file, 0, SEEK_END);
@@ -557,6 +799,7 @@
 }
 
 
+#ifndef USING_V8_SHARED
 static char* ReadToken(char* data, char token) {
   char* next = i::OS::StrChr(data, token);
   if (next != NULL) {
@@ -576,6 +819,7 @@
 static char* ReadWord(char* data) {
   return ReadToken(data, ' ');
 }
+#endif  // USING_V8_SHARED
 
 
 // Reads a file into a v8 string.
@@ -590,6 +834,11 @@
 
 
 void Shell::RunShell() {
+  Locker locker;
+  Context::Scope context_scope(evaluation_context_);
+  HandleScope handle_scope;
+  Handle<String> name = String::New("(d8)");
+#ifndef USING_V8_SHARED
   LineEditor* editor = LineEditor::Get();
   printf("V8 version %s [console: %s]\n", V8::GetVersion(), editor->name());
   if (i::FLAG_debugger) {
@@ -597,26 +846,32 @@
   }
   editor->Open();
   while (true) {
-    Locker locker;
-    HandleScope handle_scope;
-    Context::Scope context_scope(evaluation_context_);
     i::SmartPointer<char> input = editor->Prompt(Shell::kPrompt);
-    if (input.is_empty())
-      break;
+    if (input.is_empty()) break;
     editor->AddHistory(*input);
-    Handle<String> name = String::New("(d8)");
     ExecuteString(String::New(*input), name, true, true);
   }
   editor->Close();
+#else
+  printf("V8 version %s [D8 light using shared library]\n", V8::GetVersion());
+  static const int kBufferSize = 256;
+  while (true) {
+    char buffer[kBufferSize];
+    printf("%s", Shell::kPrompt);
+    if (fgets(buffer, kBufferSize, stdin) == NULL) break;
+    ExecuteString(String::New(buffer), name, true, true);
+  }
+#endif  // USING_V8_SHARED
   printf("\n");
 }
 
 
+#ifndef USING_V8_SHARED
 class ShellThread : public i::Thread {
  public:
-  ShellThread(i::Isolate* isolate, int no, i::Vector<const char> files)
-    : Thread(isolate, "d8:ShellThread"),
-      no_(no), files_(files) { }
+  ShellThread(int no, i::Vector<const char> files)
+      : Thread("d8:ShellThread"),
+        no_(no), files_(files) { }
   virtual void Run();
  private:
   int no_;
@@ -625,25 +880,6 @@
 
 
 void ShellThread::Run() {
-  // Prepare the context for this thread.
-  Locker locker;
-  HandleScope scope;
-  Handle<ObjectTemplate> global_template = ObjectTemplate::New();
-  global_template->Set(String::New("print"),
-                       FunctionTemplate::New(Shell::Print));
-  global_template->Set(String::New("write"),
-                       FunctionTemplate::New(Shell::Write));
-  global_template->Set(String::New("read"),
-                       FunctionTemplate::New(Shell::Read));
-  global_template->Set(String::New("readline"),
-                       FunctionTemplate::New(Shell::ReadLine));
-  global_template->Set(String::New("load"),
-                       FunctionTemplate::New(Shell::Load));
-  global_template->Set(String::New("yield"),
-                       FunctionTemplate::New(Shell::Yield));
-  global_template->Set(String::New("version"),
-                       FunctionTemplate::New(Shell::Version));
-
   char* ptr = const_cast<char*>(files_.start());
   while ((ptr != NULL) && (*ptr != '\0')) {
     // For each newline-separated line.
@@ -655,8 +891,10 @@
       continue;
     }
 
-    Persistent<Context> thread_context = Context::New(NULL, global_template);
-    thread_context->SetSecurityToken(Undefined());
+    // Prepare the context for this thread.
+    Locker locker;
+    HandleScope scope;
+    Persistent<Context> thread_context = Shell::CreateEvaluationContext();
     Context::Scope context_scope(thread_context);
 
     while ((ptr != NULL) && (*ptr != '\0')) {
@@ -681,118 +919,377 @@
     ptr = next_line;
   }
 }
+#endif  // USING_V8_SHARED
 
 
-int Shell::Main(int argc, char* argv[]) {
-  i::FlagList::SetFlagsFromCommandLine(&argc, argv, true);
-  if (i::FLAG_help) {
-    return 1;
-  }
-  Initialize();
-  bool run_shell = (argc == 1);
+void SourceGroup::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);
+}
 
-  // Default use preemption if threads are created.
-  bool use_preemption = true;
 
-  // Default to use lowest possible thread preemption interval to test as many
-  // edgecases as possible.
-  int preemption_interval = 1;
-
-  i::List<i::Thread*> threads(1);
-
-  {
-    // Acquire the V8 lock once initialization has finished. Since the thread
-    // below may spawn new threads accessing V8 holding the V8 lock here is
-    // mandatory.
-    Locker locker;
-    Context::Scope context_scope(evaluation_context_);
-    for (int i = 1; i < argc; i++) {
-      char* str = argv[i];
-      if (strcmp(str, "--shell") == 0) {
-        run_shell = true;
-      } else if (strcmp(str, "--preemption") == 0) {
-        use_preemption = true;
-      } else if (strcmp(str, "--no-preemption") == 0) {
-        use_preemption = false;
-      } else if (strcmp(str, "--preemption-interval") == 0) {
-        if (i + 1 < argc) {
-          char* end = NULL;
-          preemption_interval = strtol(argv[++i], &end, 10);  // NOLINT
-          if (preemption_interval <= 0 || *end != '\0' || errno == ERANGE) {
-            printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
-            return 1;
-          }
-        } else {
-          printf("Missing value for --preemption-interval\n");
-          return 1;
-       }
-      } else if (strcmp(str, "-f") == 0) {
-        // Ignore any -f flags for compatibility with 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)) {
-          OnExit();
-          return 1;
-        }
-        i++;
-      } else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
-        int size = 0;
-        const char* files = ReadChars(argv[++i], &size);
-        if (files == NULL) return 1;
-        ShellThread* thread =
-            new ShellThread(i::Isolate::Current(),
-                            threads.length(),
-                            i::Vector<const char>(files, size));
-        thread->Start();
-        threads.Add(thread);
-      } else {
-        // Use all other arguments as names of files to load and run.
-        HandleScope handle_scope;
-        Handle<String> file_name = v8::String::New(str);
-        Handle<String> source = ReadFile(str);
-        if (source.IsEmpty()) {
-          printf("Error reading '%s'\n", str);
-          return 1;
-        }
-        if (!ExecuteString(source, file_name, false, true)) {
-          OnExit();
-          return 1;
-        }
+void SourceGroup::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.
+      HandleScope handle_scope;
+      Handle<String> file_name = String::New("unnamed");
+      Handle<String> source = String::New(argv_[i + 1]);
+      if (!Shell::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.
+      HandleScope handle_scope;
+      Handle<String> file_name = String::New(arg);
+      Handle<String> source = ReadFile(arg);
+      if (source.IsEmpty()) {
+        printf("Error reading '%s'\n", arg);
+        ExitShell(1);
+        return;
+      }
+      if (!Shell::ExecuteString(source, file_name, false, true)) {
+        ExitShell(1);
+        return;
       }
     }
+  }
+}
 
+
+Handle<String> SourceGroup::ReadFile(const char* name) {
+#ifndef USING_V8_SHARED
+  FILE* file = i::OS::FOpen(name, "rb");
+#else
+  // TODO(yangguo@chromium.org): reading from a directory hangs!
+  FILE* file = fopen(name, "rb");
+#endif  // USING_V8_SHARED
+  if (file == NULL) return Handle<String>();
+
+  fseek(file, 0, SEEK_END);
+  int size = ftell(file);
+  rewind(file);
+
+  char* chars = new char[size + 1];
+  chars[size] = '\0';
+  for (int i = 0; i < size;) {
+    int read = fread(&chars[i], 1, size - i, file);
+    i += read;
+  }
+  fclose(file);
+  Handle<String> result = String::New(chars, size);
+  delete[] chars;
+  return result;
+}
+
+
+#ifndef USING_V8_SHARED
+i::Thread::Options SourceGroup::GetThreadOptions() {
+  i::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;
+}
+
+
+void SourceGroup::ExecuteInThread() {
+  Isolate* isolate = Isolate::New();
+  do {
+    if (next_semaphore_ != NULL) next_semaphore_->Wait();
+    {
+      Isolate::Scope iscope(isolate);
+      Locker lock(isolate);
+      HandleScope scope;
+      Persistent<Context> context = Shell::CreateEvaluationContext();
+      {
+        Context::Scope cscope(context);
+        Execute();
+      }
+      context.Dispose();
+    }
+    if (done_semaphore_ != NULL) done_semaphore_->Signal();
+  } while (!Shell::options.last_run);
+  isolate->Dispose();
+}
+
+
+void SourceGroup::StartExecuteInThread() {
+  if (thread_ == NULL) {
+    thread_ = new IsolateThread(this);
+    thread_->Start();
+  }
+  next_semaphore_->Signal();
+}
+
+
+void SourceGroup::WaitForThread() {
+  if (thread_ == NULL) return;
+  if (Shell::options.last_run) {
+    thread_->Join();
+    thread_ = NULL;
+  } else {
+    done_semaphore_->Wait();
+  }
+}
+#endif  // USING_V8_SHARED
+
+
+bool Shell::SetOptions(int argc, char* argv[]) {
+  for (int i = 0; i < argc; i++) {
+    if (strcmp(argv[i], "--stress-opt") == 0) {
+      options.stress_opt = true;
+      argv[i] = NULL;
+    } else if (strcmp(argv[i], "--stress-deopt") == 0) {
+      options.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.
+      options.stress_opt = false;
+      options.stress_deopt = false;
+    } else if (strcmp(argv[i], "--shell") == 0) {
+      options.interactive_shell = true;
+      argv[i] = NULL;
+    } else if (strcmp(argv[i], "--test") == 0) {
+      options.test_shell = true;
+      argv[i] = NULL;
+    } else if (strcmp(argv[i], "--preemption") == 0) {
+#ifdef USING_V8_SHARED
+      printf("D8 with shared library does not support multi-threading\n");
+      return false;
+#else
+      options.use_preemption = true;
+      argv[i] = NULL;
+#endif  // USING_V8_SHARED
+    } else if (strcmp(argv[i], "--no-preemption") == 0) {
+#ifdef USING_V8_SHARED
+      printf("D8 with shared library does not support multi-threading\n");
+      return false;
+#else
+      options.use_preemption = false;
+      argv[i] = NULL;
+#endif  // USING_V8_SHARED
+    } else if (strcmp(argv[i], "--preemption-interval") == 0) {
+#ifdef USING_V8_SHARED
+      printf("D8 with shared library does not support multi-threading\n");
+      return false;
+#else
+      if (++i < argc) {
+        argv[i-1] = NULL;
+        char* end = NULL;
+        options.preemption_interval = strtol(argv[i], &end, 10);  // NOLINT
+        if (options.preemption_interval <= 0
+            || *end != '\0'
+            || errno == ERANGE) {
+          printf("Invalid value for --preemption-interval '%s'\n", argv[i]);
+          return false;
+        }
+        argv[i] = NULL;
+      } else {
+        printf("Missing value for --preemption-interval\n");
+        return false;
+      }
+#endif  // USING_V8_SHARED
+    } else if (strcmp(argv[i], "-f") == 0) {
+      // Ignore any -f flags for compatibility with other stand-alone
+      // JavaScript engines.
+      continue;
+    } else if (strcmp(argv[i], "--isolate") == 0) {
+#ifdef USING_V8_SHARED
+      printf("D8 with shared library does not support multi-threading\n");
+      return false;
+#endif  // USING_V8_SHARED
+      options.num_isolates++;
+    }
+#ifdef USING_V8_SHARED
+    else if (strcmp(argv[i], "--dump-counters") == 0) {
+      printf("D8 with shared library does not include counters\n");
+      return false;
+    } else if (strcmp(argv[i], "-p") == 0) {
+      printf("D8 with shared library does not support multi-threading\n");
+      return false;
+    } else if (strcmp(argv[i], "--debugger") == 0) {
+      printf("Javascript debugger not included\n");
+      return false;
+    }
+#endif  // USING_V8_SHARED
+  }
+
+#ifndef USING_V8_SHARED
+  // Run parallel threads if we are not using --isolate
+  for (int i = 1; i < argc; i++) {
+    if (argv[i] == NULL) continue;
+    if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
+      if (options.num_isolates > 1) {
+        printf("-p is not compatible with --isolate\n");
+        return false;
+      }
+      argv[i] = NULL;
+      if (options.parallel_files == NULL) {
+        options.parallel_files = new i::List<i::Vector<const char> >();
+      }
+      int size = 0;
+      const char* files = ReadChars(argv[++i], &size);
+      if (files == NULL) {
+        printf("-p option incomplete\n");
+        return false;
+      }
+      argv[i] = NULL;
+      options.parallel_files->Add(i::Vector<const char>(files, size));
+    }
+  }
+#endif  // USING_V8_SHARED
+
+  v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
+
+  // set up isolated source groups
+  options.isolate_sources = new SourceGroup[options.num_isolates];
+  SourceGroup* current = options.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 (strncmp(argv[i], "--", 2) == 0) {
+      printf("Warning: unknown flag %s.\nTry --help for options\n", argv[i]);
+    }
+  }
+  current->End(argc);
+
+  return true;
+}
+
+
+int Shell::RunMain(int argc, char* argv[]) {
+#ifndef USING_V8_SHARED
+  i::List<i::Thread*> threads(1);
+  if (options.parallel_files != NULL)
+    for (int i = 0; i < options.parallel_files->length(); i++) {
+      i::Vector<const char> files = options.parallel_files->at(i);
+      ShellThread* thread = new ShellThread(threads.length(), files);
+      thread->Start();
+      threads.Add(thread);
+    }
+
+  for (int i = 1; i < options.num_isolates; ++i) {
+    options.isolate_sources[i].StartExecuteInThread();
+  }
+#endif  // USING_V8_SHARED
+  {  // NOLINT
+    Locker lock;
+    HandleScope scope;
+    Persistent<Context> context = CreateEvaluationContext();
+    if (options.last_run) {
+      // Keep using the same context in the interactive shell.
+      evaluation_context_ = context;
+#ifndef V8_SHARED
+      // If the interactive debugger is enabled make sure to activate
+      // it before running the files passed on the command line.
+      if (i::FLAG_debugger) {
+        InstallUtilityScript();
+      }
+#endif  // V8_SHARED
+    }
+    {
+      Context::Scope cscope(context);
+      options.isolate_sources[0].Execute();
+    }
+    if (!options.last_run) {
+      context.Dispose();
+    }
+
+#ifndef USING_V8_SHARED
     // Start preemption if threads have been created and preemption is enabled.
-    if (threads.length() > 0 && use_preemption) {
-      Locker::StartPreemption(preemption_interval);
+    if (options.parallel_files != NULL
+        && threads.length() > 0
+        && options.use_preemption) {
+      Locker::StartPreemption(options.preemption_interval);
+    }
+#endif  // USING_V8_SHARED
+  }
+
+#ifndef USING_V8_SHARED
+  for (int i = 1; i < options.num_isolates; ++i) {
+    options.isolate_sources[i].WaitForThread();
+  }
+
+  if (options.parallel_files != NULL)
+    for (int i = 0; i < threads.length(); i++) {
+      i::Thread* thread = threads[i];
+      thread->Join();
+      delete thread;
     }
 
-#ifdef ENABLE_DEBUGGER_SUPPORT
-    // Run the remote debugger if requested.
-    if (i::FLAG_remote_debugger) {
-      RunRemoteDebugger(i::FLAG_debugger_port);
-      return 0;
-    }
-#endif
-  }
-  if (run_shell)
-    RunShell();
-  for (int i = 0; i < threads.length(); i++) {
-    i::Thread* thread = threads[i];
-    thread->Join();
-    delete thread;
-  }
   OnExit();
+#endif  // USING_V8_SHARED
   return 0;
 }
 
 
+int Shell::Main(int argc, char* argv[]) {
+  if (!SetOptions(argc, argv)) return 1;
+  Initialize();
+
+  int result = 0;
+  if (options.stress_opt || options.stress_deopt) {
+    Testing::SetStressRunType(
+        options.stress_opt ? Testing::kStressTypeOpt
+                           : Testing::kStressTypeDeopt);
+    int stress_runs = Testing::GetStressRuns();
+    for (int i = 0; i < stress_runs && result == 0; i++) {
+      printf("============ Stress %d/%d ============\n", i + 1, stress_runs);
+      Testing::PrepareStressRun(i);
+      options.last_run = (i == stress_runs - 1);
+      result = RunMain(argc, argv);
+    }
+    printf("======== Full Deoptimization =======\n");
+    Testing::DeoptimizeAll();
+  } else {
+    result = RunMain(argc, argv);
+  }
+
+
+#if !defined(USING_V8_SHARED) && defined(ENABLE_DEBUGGER_SUPPORT)
+  // Run remote debugger if requested, but never on --test
+  if (i::FLAG_remote_debugger && !options.test_shell) {
+    InstallUtilityScript();
+    RunRemoteDebugger(i::FLAG_debugger_port);
+    return 0;
+  }
+#endif  // !USING_V8_SHARED && ENABLE_DEBUGGER_SUPPORT
+
+  // Run interactive shell if explicitly requested or if no script has been
+  // executed, but never on --test
+
+  if (( options.interactive_shell
+      || !options.script_executed )
+      && !options.test_shell ) {
+#ifndef USING_V8_SHARED
+    if (!i::FLAG_debugger) {
+      InstallUtilityScript();
+    }
+#endif  // USING_V8_SHARED
+    RunShell();
+  }
+
+  V8::Dispose();
+
+  return result;
+}
+
 }  // namespace v8