Arguments on the command line are made available as a global "arguments" array.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 11 Nov 2008 14:16:24 +0000 (14:16 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 11 Nov 2008 14:16:24 +0000 (14:16 +0000)
Fix for non-empty assertion in debug mode (string representation of empty arguments is a single space, not an empty string).

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@733 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/d8.cc
src/disassembler.cc
src/flag-definitions.h
src/flags.cc
src/flags.h
src/log.cc
src/serialize.cc
src/string-stream.cc
src/string-stream.h
test/cctest/test-flags.cc

index 67e8c8e..480d4ae 100644 (file)
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -235,6 +235,19 @@ void Shell::Initialize() {
   utility_context_->SetSecurityToken(Undefined());
   Context::Scope utility_scope(utility_context_);
 
+  i::JSArguments js_args = i::FLAG_js_arguments;
+  i::Handle<i::FixedArray> arguments_array =
+      i::Factory::NewFixedArray(js_args.argc());
+  for (int j = 0; j < js_args.argc(); j++) {
+    i::Handle<i::String> arg =
+        i::Factory::NewStringFromUtf8(i::CStrVector(js_args[j]));
+    arguments_array->set(j, *arg);
+  }
+  i::Handle<i::JSArray> arguments_jsarray =
+      i::Factory::NewJSArrayWithElements(arguments_array);
+  global_template->Set(String::New("arguments"),
+                       Utils::ToLocal(arguments_jsarray));
+
   // Install the debugger object in the utility scope
   i::Debug::Load();
   i::Debug::debug_context()->set_security_token(i::Heap::undefined_value());
index 12183d5..53f594f 100644 (file)
@@ -217,7 +217,7 @@ static int DecodeIt(FILE* f,
         HeapStringAllocator allocator;
         StringStream accumulator(&allocator);
         relocinfo.target_object()->ShortPrint(&accumulator);
-        SmartPointer<char> obj_name = accumulator.ToCString();
+        SmartPointer<const char> obj_name = accumulator.ToCString();
         out.AddFormatted("    ;; object: %s", *obj_name);
       } else if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
         const char* reference_name =
index 6e2462b..5c96429 100644 (file)
 #error No mode supplied when including flags.defs
 #endif
 
+#ifdef FLAG_MODE_DECLARE
+// Structure used to hold a collection of arguments to the JavaScript code.
+struct JSArguments {
+public:
+  JSArguments();
+  JSArguments(int argc, const char** argv);
+  int argc() const;
+  const char** argv();
+  const char*& operator[](int idx);
+  JSArguments& operator=(JSArguments args);
+private:
+  int argc_;
+  const char** argv_;
+};
+#endif
+
 #define DEFINE_bool(nam, def, cmt) FLAG(BOOL, bool, nam, def, cmt)
 #define DEFINE_int(nam, def, cmt) FLAG(INT, int, nam, def, cmt)
 #define DEFINE_float(nam, def, cmt) FLAG(FLOAT, double, nam, def, cmt)
 #define DEFINE_string(nam, def, cmt) FLAG(STRING, const char*, nam, def, cmt)
+#define DEFINE_args(nam, def, cmt) FLAG(ARGS, JSArguments, nam, def, cmt)
 
 //
 // Flags in all modes.
@@ -202,6 +219,8 @@ DEFINE_string(testing_serialization_file, "/tmp/serdes",
 
 DEFINE_bool(help, false, "Print usage message, including flags, on console")
 DEFINE_bool(dump_counters, false, "Dump counters on exit")
+DEFINE_args(js_arguments, JSArguments(),
+            "Pass all remaining arguments to the script. Alias for \"--\".")
 
 //
 // Debug only flags
index 4daea39..364cf7d 100644 (file)
@@ -31,6 +31,9 @@
 #include "v8.h"
 
 #include "platform.h"
+#include "smart-pointer.h"
+#include "string-stream.h"
+
 
 namespace v8 { namespace internal {
 
@@ -48,7 +51,7 @@ namespace {
 // to the actual flag, default value, comment, etc.  This is designed to be POD
 // initialized as to avoid requiring static constructors.
 struct Flag {
-  enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING };
+  enum FlagType { TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_ARGS };
 
   FlagType type_;           // What type of flag, bool, int, or string.
   const char* name_;        // Name of the flag, ex "my_flag".
@@ -82,6 +85,11 @@ struct Flag {
     return reinterpret_cast<const char**>(valptr_);
   }
 
+  JSArguments* args_variable() const {
+    ASSERT(type_ == TYPE_ARGS);
+    return reinterpret_cast<JSArguments*>(valptr_);
+  }
+
   bool bool_default() const {
     ASSERT(type_ == TYPE_BOOL);
     return *reinterpret_cast<const bool*>(defptr_);
@@ -102,6 +110,11 @@ struct Flag {
     return *reinterpret_cast<const char* const *>(defptr_);
   }
 
+  JSArguments args_default() const {
+    ASSERT(type_ == TYPE_ARGS);
+    return *reinterpret_cast<const JSArguments*>(defptr_);
+  }
+
   // Compare this flag's current value against the default.
   bool IsDefault() const {
     switch (type_) {
@@ -111,12 +124,15 @@ struct Flag {
         return *int_variable() == int_default();
       case TYPE_FLOAT:
         return *float_variable() == float_default();
-      case TYPE_STRING:
+      case TYPE_STRING: {
         const char* str1 = *string_variable();
         const char* str2 = string_default();
         if (str2 == NULL) return str1 == NULL;
         if (str1 == NULL) return str2 == NULL;
         return strcmp(str1, str2) == 0;
+      }
+      case TYPE_ARGS:
+        return args_variable()->argc() == 0;
     }
     UNREACHABLE();
     return true;
@@ -137,6 +153,9 @@ struct Flag {
       case TYPE_STRING:
         *string_variable() = string_default();
         break;
+      case TYPE_ARGS:
+        *args_variable() = args_default();
+        break;
     }
   }
 };
@@ -157,67 +176,81 @@ static const char* Type2String(Flag::FlagType type) {
     case Flag::TYPE_INT: return "int";
     case Flag::TYPE_FLOAT: return "float";
     case Flag::TYPE_STRING: return "string";
+    case Flag::TYPE_ARGS: return "arguments";
   }
   UNREACHABLE();
   return NULL;
 }
 
 
-static char* ToString(Flag* flag) {
-  Vector<char> value;
+static SmartPointer<const char> ToString(Flag* flag) {
+  HeapStringAllocator string_allocator;
+  StringStream buffer(&string_allocator);
   switch (flag->type()) {
     case Flag::TYPE_BOOL:
-      value = Vector<char>::New(6);
-      OS::SNPrintF(value, "%s", (*flag->bool_variable() ? "true" : "false"));
+      buffer.Add("%s", (*flag->bool_variable() ? "true" : "false"));
       break;
     case Flag::TYPE_INT:
-      value = Vector<char>::New(12);
-      OS::SNPrintF(value, "%d", *flag->int_variable());
+      buffer.Add("%d", *flag->int_variable());
       break;
     case Flag::TYPE_FLOAT:
-      value = Vector<char>::New(20);
-      OS::SNPrintF(value, "%f", *flag->float_variable());
+      buffer.Add("%f", FmtElm(*flag->float_variable()));
       break;
-    case Flag::TYPE_STRING:
+    case Flag::TYPE_STRING: {
       const char* str = *flag->string_variable();
-      if (str) {
-        int length = strlen(str) + 1;
-        value = Vector<char>::New(length);
-        OS::SNPrintF(value, "%s", str);
-      } else {
-        value = Vector<char>::New(5);
-        OS::SNPrintF(value, "NULL");
+      buffer.Add("%s", str ? str : "NULL");
+      break;
+    }
+    case Flag::TYPE_ARGS: {
+      JSArguments args = *flag->args_variable();
+      if (args.argc() > 0) {
+        buffer.Add("%s",  args[0]);
+        for (int i = 1; i < args.argc(); i++) {
+          buffer.Add(" %s", args[i]);
+        }
       }
       break;
+    }
   }
-  ASSERT(!value.is_empty());
-  return value.start();
+  return buffer.ToCString();
 }
 
 
 // static
-List<char *>* FlagList::argv() {
-  List<char *>* args = new List<char*>(8);
+List<const char*>* FlagList::argv() {
+  List<const char*>* args = new List<const char*>(8);
+  Flag* args_flag = NULL;
   for (size_t i = 0; i < num_flags; ++i) {
     Flag* f = &flags[i];
     if (!f->IsDefault()) {
-      Vector<char> cmdline_flag;
+      if (f->type() == Flag::TYPE_ARGS) {
+        ASSERT(args_flag == NULL);
+        args_flag = f;  // Must be last in arguments.
+        continue;
+      }
+      HeapStringAllocator string_allocator;
+      StringStream buffer(&string_allocator);
       if (f->type() != Flag::TYPE_BOOL || *(f->bool_variable())) {
-        int length = strlen(f->name()) + 2 + 1;
-        cmdline_flag = Vector<char>::New(length);
-        OS::SNPrintF(cmdline_flag, "--%s", f->name());
+        buffer.Add("--%s", f->name());
       } else {
-        int length = strlen(f->name()) + 4 + 1;
-        cmdline_flag = Vector<char>::New(length);
-        OS::SNPrintF(cmdline_flag, "--no%s", f->name());
+        buffer.Add("--no%s", f->name());
       }
-      args->Add(cmdline_flag.start());
+      args->Add(buffer.ToCString().Detach());
       if (f->type() != Flag::TYPE_BOOL) {
-        args->Add(ToString(f));
+        args->Add(ToString(f).Detach());
       }
     }
   }
-
+  if (args_flag != NULL) {
+    HeapStringAllocator string_allocator;
+    StringStream buffer(&string_allocator);
+    buffer.Add("--%s", args_flag->name());
+    args->Add(buffer.ToCString().Detach());
+    JSArguments jsargs = *args_flag->args_variable();
+    for (int j = 0; j < jsargs.argc(); j++) {
+      args->Add(reinterpret_cast<const char*>(strdup(jsargs[j])));
+    }
+  }
   return args;
 }
 
@@ -239,8 +272,14 @@ static void SplitArgument(const char* arg,
   if (*arg == '-') {
     // find the begin of the flag name
     arg++;  // remove 1st '-'
-    if (*arg == '-')
+    if (*arg == '-') {
       arg++;  // remove 2nd '-'
+      if (arg[0] == '\0') {
+        const char* kJSArgumentsFlagName = "js_arguments";
+        *name = kJSArgumentsFlagName;
+        return;
+      }
+    }
     if (arg[0] == 'n' && arg[1] == 'o') {
       arg += 2;  // remove "no"
       *is_bool = true;
@@ -324,7 +363,9 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
       }
 
       // if we still need a flag value, use the next argument if available
-      if (flag->type() != Flag::TYPE_BOOL && value == NULL) {
+      if (flag->type() != Flag::TYPE_BOOL &&
+          flag->type() != Flag::TYPE_ARGS &&
+          value == NULL) {
         if (i < *argc) {
           value = argv[i++];
         } else {
@@ -350,6 +391,20 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
         case Flag::TYPE_STRING:
           *flag->string_variable() = value;
           break;
+        case Flag::TYPE_ARGS: {
+          int start_pos = (value == NULL) ? i : i - 1;
+          int js_argc = *argc - start_pos;
+          const char** js_argv = NewArray<const char*>(js_argc);
+          if (value != NULL) {
+            js_argv[0] = value;
+          }
+          for (int k = i; k < *argc; k++) {
+            js_argv[k - start_pos] = argv[k];
+          }
+          *flag->args_variable() = JSArguments(js_argc, js_argv);
+          i = *argc;  // Consume all arguments
+          break;
+        }
       }
 
       // handle errors
@@ -363,9 +418,11 @@ int FlagList::SetFlagsFromCommandLine(int* argc,
       }
 
       // remove the flag & value from the command
-      if (remove_flags)
-        while (j < i)
+      if (remove_flags) {
+        while (j < i) {
           argv[j++] = NULL;
+        }
+      }
     }
   }
 
@@ -467,11 +524,24 @@ void FlagList::PrintHelp() {
   printf("Options:\n");
   for (size_t i = 0; i < num_flags; ++i) {
     Flag* f = &flags[i];
-    char* value = ToString(f);
+    SmartPointer<const char> value = ToString(f);
     printf("  --%s (%s)\n        type: %s  default: %s\n",
-           f->name(), f->comment(), Type2String(f->type()), value);
-    DeleteArray(value);
+           f->name(), f->comment(), Type2String(f->type()), *value);
   }
 }
 
+JSArguments::JSArguments()
+    : argc_(0), argv_(NULL) {}
+JSArguments::JSArguments(int argc, const char** argv)
+    : argc_(argc), argv_(argv) {}
+int JSArguments::argc() const { return argc_; }
+const char** JSArguments::argv() { return argv_; }
+const char*& JSArguments::operator[](int idx) { return argv_[idx]; }
+JSArguments& JSArguments::operator=(JSArguments args) {
+    argc_ = args.argc_;
+    argv_ = args.argv_;
+    return *this;
+}
+
+
 } }  // namespace v8::internal
index 813ea95..e6cbe3c 100644 (file)
@@ -43,14 +43,15 @@ class FlagList {
   // argv array passed to the main function, e.g.
   // ("--prof", "--log-file", "v8.prof", "--nolazy").
   //
-  // The caller is responsible for disposing the list.
-  static List<char *>* argv();
+  // The caller is responsible for disposing the list, as well
+  // as every element of it.
+  static List<const char*>* argv();
 
   // Set the flag values by parsing the command line. If remove_flags is
   // set, the flags and associated values are removed from (argc,
   // argv). Returns 0 if no error occurred. Otherwise, returns the argv
   // index > 0 for the argument where an error occurred. In that case,
-  // (argc, argv) will remain unchanged indepdendent of the remove_flags
+  // (argc, argv) will remain unchanged independent of the remove_flags
   // value, and no assumptions about flag settings should be made.
   //
   // The following syntax for flags is accepted (both '-' and '--' are ok):
@@ -59,6 +60,7 @@ class FlagList {
   //   --noflag      (bool flags only)
   //   --flag=value  (non-bool flags only, no spaces around '=')
   //   --flag value  (non-bool flags only)
+  //   --            (equivalent to --js_arguments, captures all remaining args)
   static int SetFlagsFromCommandLine(int* argc, char** argv, bool remove_flags);
 
   // Set the flag values by parsing the string str. Splits string into argc
index bd85fea..803dfe8 100644 (file)
@@ -728,7 +728,7 @@ bool Logger::Setup() {
           stream.Put(*p);
         }
       }
-      SmartPointer<char> expanded = stream.ToCString();
+      SmartPointer<const char> expanded = stream.ToCString();
       logfile_ = OS::FOpen(*expanded, "w");
     } else {
       logfile_ = OS::FOpen(FLAG_logfile, "w");
index cd7a323..359d627 100644 (file)
@@ -966,7 +966,7 @@ class GlobalHandlesRetriever: public ObjectVisitor {
 
 void Serializer::PutFlags() {
   writer_->PutC('F');
-  List<char*>* argv = FlagList::argv();
+  List<const char*>* argv = FlagList::argv();
   writer_->PutInt(argv->length());
   writer_->PutC('[');
   for (int i = 0; i < argv->length(); i++) {
index 81cbea5..6a3737b 100644 (file)
@@ -141,6 +141,13 @@ void StringStream::Add(const char* format, Vector<FmtElm> elms) {
       Add(formatted.start());
       break;
     }
+    case 'f': case 'g': case 'G': case 'e': case 'E': {
+      double value = current.data_.u_double_;
+      EmbeddedVector<char, 28> formatted;
+      OS::SNPrintF(formatted, temp.start(), value);
+      Add(formatted.start());
+      break;
+    }
     default:
       UNREACHABLE();
       break;
@@ -207,11 +214,11 @@ void StringStream::Add(const char* format, FmtElm arg0, FmtElm arg1,
 }
 
 
-SmartPointer<char> StringStream::ToCString() {
+SmartPointer<const char> StringStream::ToCString() {
   char* str = NewArray<char>(length_ + 1);
   memcpy(str, buffer_, length_);
   str[length_] = '\0';
-  return SmartPointer<char>(str);
+  return SmartPointer<const char>(str);
 }
 
 
index 9cff319..2fb29af 100644 (file)
@@ -73,16 +73,18 @@ class NoAllocationStringAllocator: public StringAllocator {
 class FmtElm {
  public:
   FmtElm(int value) : type_(INT) { data_.u_int_ = value; }  // NOLINT
+  explicit FmtElm(double value) : type_(DOUBLE) { data_.u_double_ = value; }  // NOLINT
   FmtElm(const char* value) : type_(C_STR) { data_.u_c_str_ = value; }  // NOLINT
   FmtElm(Object* value) : type_(OBJ) { data_.u_obj_ = value; }  // NOLINT
   FmtElm(Handle<Object> value) : type_(HANDLE) { data_.u_handle_ = value.location(); }  // NOLINT
   FmtElm(void* value) : type_(INT) { data_.u_int_ = reinterpret_cast<int>(value); }  // NOLINT
  private:
   friend class StringStream;
-  enum Type { INT, C_STR, OBJ, HANDLE };
+  enum Type { INT, DOUBLE, C_STR, OBJ, HANDLE };
   Type type_;
   union {
     int u_int_;
+    double u_double_;
     const char* u_c_str_;
     Object* u_obj_;
     Object** u_handle_;
@@ -116,7 +118,7 @@ class StringStream {
   void OutputToStdOut();
   void Log();
   Handle<String> ToString();
-  SmartPointer<char> ToCString();
+  SmartPointer<const char> ToCString();
 
   // Object printing support.
   void PrintName(Object* o);
index a3aa4b2..9019a89 100644 (file)
@@ -168,3 +168,67 @@ TEST(Flags6b) {
   const char* str = "       --testing-int-flag 0      --testing_float_flag    ";
   CHECK_EQ(3, FlagList::SetFlagsFromString(str, strlen(str)));
 }
+
+
+TEST(FlagsJSArguments1) {
+  SetFlagsToDefault();
+  int argc = 6;
+  const char* argv[] = {"TestJSArgs1",
+                        "--testing-int-flag", "42",
+                        "--", "testing-float-flag", "7"};
+  CHECK_EQ(0, FlagList::SetFlagsFromCommandLine(&argc,
+                                                const_cast<char **>(argv),
+                                                true));
+  CHECK_EQ(42, FLAG_testing_int_flag);
+  CHECK_EQ(2.5, FLAG_testing_float_flag);
+  CHECK_EQ(2, FLAG_js_arguments.argc());
+  CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag"));
+  CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7"));
+  CHECK_EQ(1, argc);
+}
+
+
+TEST(FlagsJSArguments1b) {
+  SetFlagsToDefault();
+  const char* str = "--testing-int-flag 42 -- testing-float-flag 7";
+  CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+  CHECK_EQ(42, FLAG_testing_int_flag);
+  CHECK_EQ(2.5, FLAG_testing_float_flag);
+  CHECK_EQ(2, FLAG_js_arguments.argc());
+  CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag"));
+  CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7"));
+}
+
+
+TEST(FlagsJSArguments2) {
+  SetFlagsToDefault();
+  const char* str = "--testing-int-flag 42 --js-arguments testing-float-flag 7";
+  CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+  CHECK_EQ(42, FLAG_testing_int_flag);
+  CHECK_EQ(2.5, FLAG_testing_float_flag);
+  CHECK_EQ(2, FLAG_js_arguments.argc());
+  CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag"));
+  CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7"));
+}
+
+
+TEST(FlagsJSArguments3) {
+  SetFlagsToDefault();
+  const char* str = "--testing-int-flag 42 --js-arguments=testing-float-flag 7";
+  CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+  CHECK_EQ(42, FLAG_testing_int_flag);
+  CHECK_EQ(2.5, FLAG_testing_float_flag);
+  CHECK_EQ(2, FLAG_js_arguments.argc());
+  CHECK_EQ(0, strcmp(FLAG_js_arguments[0], "testing-float-flag"));
+  CHECK_EQ(0, strcmp(FLAG_js_arguments[1], "7"));
+}
+
+
+TEST(FlagsJSArguments4) {
+  SetFlagsToDefault();
+  const char* str = "--testing-int-flag 42 --";
+  CHECK_EQ(0, FlagList::SetFlagsFromString(str, strlen(str)));
+  CHECK_EQ(42, FLAG_testing_int_flag);
+  CHECK_EQ(0, FLAG_js_arguments.argc());
+}
+