Author: [email protected]
Date: Thu Mar 26 17:24:49 2009
New Revision: 1622

Modified:
    branches/bleeding_edge/include/v8.h
    branches/bleeding_edge/samples/shell.cc
    branches/bleeding_edge/src/api.cc
    branches/bleeding_edge/src/debug.cc
    branches/bleeding_edge/src/debug.h
    branches/bleeding_edge/src/flag-definitions.h
    branches/bleeding_edge/src/flags.cc
    branches/bleeding_edge/src/log.cc
    branches/bleeding_edge/src/log.h
    branches/bleeding_edge/src/platform-linux.cc
    branches/bleeding_edge/src/v8.cc
    branches/bleeding_edge/src/zone-inl.h
    branches/bleeding_edge/src/zone.h
    branches/bleeding_edge/test/cctest/cctest.cc
    branches/bleeding_edge/test/cctest/test-api.cc
    branches/bleeding_edge/test/cctest/test-strings.cc
    branches/bleeding_edge/test/message/testcfg.py

Log:
Fixed a bunch of memory leaks in tests, including:
  - String traversal test data (now in a zone)
  - Debug message thread (now joined on exit)
  - Threading test threads (now joined on exit)
  - Changed message tests framework to cope with valgrind
Also, fixed a bug where we'd try to delete stack-allocated objects
when tearing down v8.  Good times.


Modified: branches/bleeding_edge/include/v8.h
==============================================================================
--- branches/bleeding_edge/include/v8.h (original)
+++ branches/bleeding_edge/include/v8.h Thu Mar 26 17:24:49 2009
@@ -1080,13 +1080,13 @@
     * access check info, the object cannot be accessed by anyone.
     */
    void TurnOnAccessCheck();
-
+
    /**
     * Returns the identity hash for this object. The current implemenation  
uses
     * a hidden property on the object to store the identity hash.
     */
    int GetIdentityHash();
-
+
    /**
     * Access hidden properties on JavaScript objects. These properties are
     * hidden from the executing JavaScript and only accessible through the  
V8
@@ -2032,6 +2032,17 @@
     * See also PauseProfiler().
     */
    static void ResumeProfiler();
+
+  /**
+   * Releases any resources used by v8 and stops any utility threads
+   * that may be running.  Note that disposing v8 is permanent, it
+   * cannot be reinitialized.
+   *
+   * It should generally not be necessary to dispose v8 before exiting
+   * a process, this should happen automatically.  It is only necessary
+   * to use if the process needs the resources taken up by v8.
+   */
+  static bool Dispose();

   private:
    V8();

Modified: branches/bleeding_edge/samples/shell.cc
==============================================================================
--- branches/bleeding_edge/samples/shell.cc     (original)
+++ branches/bleeding_edge/samples/shell.cc     Thu Mar 26 17:24:49 2009
@@ -45,7 +45,7 @@
  void ReportException(v8::TryCatch* handler);


-int main(int argc, char* argv[]) {
+int RunMain(int argc, char* argv[]) {
    v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
    v8::HandleScope handle_scope;
    // Create a template for the global object.
@@ -95,8 +95,14 @@
          return 1;
      }
    }
-  if (run_shell) RunShell(context);
    return 0;
+}
+
+
+int main(int argc, char* argv[]) {
+  int result = RunMain(argc, argv);
+  v8::V8::Dispose();
+  return result;
  }



Modified: branches/bleeding_edge/src/api.cc
==============================================================================
--- branches/bleeding_edge/src/api.cc   (original)
+++ branches/bleeding_edge/src/api.cc   Thu Mar 26 17:24:49 2009
@@ -2272,6 +2272,12 @@
  }


+bool v8::V8::Dispose() {
+  i::V8::TearDown();
+  return true;
+}
+
+
  const char* v8::V8::GetVersion() {
    return "1.1.4 (candidate)";
  }

Modified: branches/bleeding_edge/src/debug.cc
==============================================================================
--- branches/bleeding_edge/src/debug.cc (original)
+++ branches/bleeding_edge/src/debug.cc Thu Mar 26 17:24:49 2009
@@ -1737,6 +1737,15 @@
  }


+void Debugger::TearDown() {
+  if (message_thread_ != NULL) {
+    message_thread_->Stop();
+    delete message_thread_;
+    message_thread_ = NULL;
+  }
+}
+
+
  void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void*  
data) {
    message_handler_ = handler;
    message_handler_data_ = data;
@@ -1852,16 +1861,23 @@
  DebugMessageThread::DebugMessageThread()
      : host_running_(true),
        command_queue_(kQueueInitialSize),
-      message_queue_(kQueueInitialSize) {
+      message_queue_(kQueueInitialSize),
+      keep_running_(true) {
    command_received_ = OS::CreateSemaphore(0);
    message_received_ = OS::CreateSemaphore(0);
  }

-// Does not free resources held by DebugMessageThread
-// because this cannot be done thread-safely.
+// Should only be done after the thread is done running.
  DebugMessageThread::~DebugMessageThread() {
+  delete command_received_;
+  delete message_received_;
  }

+void DebugMessageThread::Stop() {
+  keep_running_ = false;
+  SendMessage(Vector<uint16_t>(NULL, 0));
+  Join();
+}

  // Puts an event coming from V8 on the queue.  Creates
  // a copy of the JSON formatted event string managed by the V8.
@@ -1909,7 +1925,7 @@

  void DebugMessageThread::Run() {
    // Sends debug events to an installed debugger message callback.
-  while (true) {
+  while (keep_running_) {
      // Wait and Get are paired so that semaphore count equals queue length.
      message_received_->Wait();
      Logger::DebugTag("Get message from event message_queue.");

Modified: branches/bleeding_edge/src/debug.h
==============================================================================
--- branches/bleeding_edge/src/debug.h  (original)
+++ branches/bleeding_edge/src/debug.h  Thu Mar 26 17:24:49 2009
@@ -429,6 +429,7 @@
                                  bool auto_continue);
    static void SetEventListener(Handle<Object> callback, Handle<Object>  
data);
    static void SetMessageHandler(v8::DebugMessageHandler handler, void*  
data);
+  static void TearDown();
    static void SetHostDispatchHandler(v8::DebugHostDispatchHandler handler,
                                       void* data);
    static void SendMessage(Vector<uint16_t> message);
@@ -527,7 +528,7 @@
  class DebugMessageThread: public Thread {
   public:
    DebugMessageThread();  // Called from API thread.
-  virtual ~DebugMessageThread();  // Never called.
+  virtual ~DebugMessageThread();
    // Called by V8 thread.  Reports events from V8 VM.
    // Also handles command processing in stopped state of V8,
    // when host_running_ is false.
@@ -554,6 +555,7 @@

    // Check whether there are commands in the queue.
    bool HasCommands() { return !command_queue_.IsEmpty(); }
+  void Stop();

    bool host_running_;  // Is the debugging host running or stopped?
    Semaphore* command_received_;  // Non-zero when command queue is  
non-empty.
@@ -564,6 +566,7 @@
    static const int kQueueInitialSize = 4;
    LockingMessageQueue command_queue_;
    LockingMessageQueue message_queue_;
+  bool keep_running_;
    DISALLOW_COPY_AND_ASSIGN(DebugMessageThread);
  };


Modified: branches/bleeding_edge/src/flag-definitions.h
==============================================================================
--- branches/bleeding_edge/src/flag-definitions.h       (original)
+++ branches/bleeding_edge/src/flag-definitions.h       Thu Mar 26 17:24:49 2009
@@ -62,7 +62,7 @@
  // printing / etc in the flag parser code.  We only do this for writable  
flags.
  #elif defined(FLAG_MODE_META)
  #define FLAG_FULL(ftype, ctype, nam, def, cmt) \
-  { Flag::TYPE_##ftype, #nam, &FLAG_##nam, &FLAGDEFAULT_##nam, cmt },
+  { Flag::TYPE_##ftype, #nam, &FLAG_##nam, &FLAGDEFAULT_##nam, cmt, false  
},
  #define FLAG_READONLY(ftype, ctype, nam, def, cmt)

  #else

Modified: branches/bleeding_edge/src/flags.cc
==============================================================================
--- branches/bleeding_edge/src/flags.cc (original)
+++ branches/bleeding_edge/src/flags.cc Thu Mar 26 17:24:49 2009
@@ -58,6 +58,7 @@
    void* valptr_;            // Pointer to the global flag variable.
    const void* defptr_;      // Pointer to the default value.
    const char* cmt_;         // A comment about the flags purpose.
+  bool owns_ptr_;           // Does the flag own its string value?

    FlagType type() const { return type_; }

@@ -80,9 +81,17 @@
      return reinterpret_cast<double*>(valptr_);
    }

-  const char** string_variable() const {
+  const char* string_value() const {
      ASSERT(type_ == TYPE_STRING);
-    return reinterpret_cast<const char**>(valptr_);
+    return *reinterpret_cast<const char**>(valptr_);
+  }
+
+  void set_string_value(const char *value, bool owns_ptr) {
+    ASSERT(type_ == TYPE_STRING);
+    const char **ptr = reinterpret_cast<const char **>(valptr_);
+    if (owns_ptr_ && *ptr != NULL) DeleteArray(*ptr);
+    *ptr = value;
+    owns_ptr_ = owns_ptr;
    }

    JSArguments* args_variable() const {
@@ -125,7 +134,7 @@
        case TYPE_FLOAT:
          return *float_variable() == float_default();
        case TYPE_STRING: {
-        const char* str1 = *string_variable();
+        const char* str1 = string_value();
          const char* str2 = string_default();
          if (str2 == NULL) return str1 == NULL;
          if (str1 == NULL) return str2 == NULL;
@@ -151,7 +160,7 @@
          *float_variable() = float_default();
          break;
        case TYPE_STRING:
-        *string_variable() = string_default();
+        set_string_value(string_default(), false);
          break;
        case TYPE_ARGS:
          *args_variable() = args_default();
@@ -197,7 +206,7 @@
        buffer.Add("%f", FmtElm(*flag->float_variable()));
        break;
      case Flag::TYPE_STRING: {
-      const char* str = *flag->string_variable();
+      const char* str = flag->string_value();
        buffer.Add("%s", str ? str : "NULL");
        break;
      }
@@ -389,17 +398,17 @@
            *flag->float_variable() = strtod(value, &endp);
            break;
          case Flag::TYPE_STRING:
-          *flag->string_variable() = value;
+          flag->set_string_value(value ? StrDup(value) : NULL, true);
            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;
+            js_argv[0] = StrDup(value);
            }
            for (int k = i; k < *argc; k++) {
-            js_argv[k - start_pos] = argv[k];
+            js_argv[k - start_pos] = StrDup(argv[k]);
            }
            *flag->args_variable() = JSArguments(js_argc, js_argv);
            i = *argc;  // Consume all arguments
@@ -491,11 +500,7 @@

    // cleanup
    DeleteArray(argv);
-  // don't delete copy0 since the substrings
-  // may be pointed to by FLAG variables!
-  // (this is a memory leak, but it's minor since this
-  // code is only used for debugging, or perhaps once
-  // during initialization).
+  DeleteArray(copy0);

    return result;
  }

Modified: branches/bleeding_edge/src/log.cc
==============================================================================
--- branches/bleeding_edge/src/log.cc   (original)
+++ branches/bleeding_edge/src/log.cc   Thu Mar 26 17:24:49 2009
@@ -407,6 +407,7 @@
  Profiler* Logger::profiler_ = NULL;
  Mutex* Logger::mutex_ = NULL;
  VMState* Logger::current_state_ = NULL;
+VMState Logger::bottom_state_(OTHER);
  SlidingStateWindow* Logger::sliding_state_window_ = NULL;

  #endif  // ENABLE_LOGGING_AND_PROFILING
@@ -1017,7 +1018,7 @@
      mutex_ = OS::CreateMutex();
    }

-  current_state_ = new VMState(OTHER);
+  current_state_ = &bottom_state_;

    // as log is initialized early with V8, we can assume that JS execution
    // frames can never reach this point on stack
@@ -1052,8 +1053,6 @@
      profiler_ = NULL;
    }

-  // Deleting the current_state_ has the side effect of assigning to it(!).
-  while (current_state_) delete current_state_;
    delete sliding_state_window_;

    delete ticker_;

Modified: branches/bleeding_edge/src/log.h
==============================================================================
--- branches/bleeding_edge/src/log.h    (original)
+++ branches/bleeding_edge/src/log.h    Thu Mar 26 17:24:49 2009
@@ -83,7 +83,7 @@
  #endif


-class VMState {
+class VMState BASE_EMBEDDED {
  #ifdef ENABLE_LOGGING_AND_PROFILING
   public:
    explicit VMState(StateTag state);
@@ -251,6 +251,9 @@

    // A stack of VM states.
    static VMState* current_state_;
+
+  // Singleton bottom or default vm state.
+  static VMState bottom_state_;

    // SlidingStateWindow instance keeping a sliding window of the most
    // recent VM states.

Modified: branches/bleeding_edge/src/platform-linux.cc
==============================================================================
--- branches/bleeding_edge/src/platform-linux.cc        (original)
+++ branches/bleeding_edge/src/platform-linux.cc        Thu Mar 26 17:24:49 2009
@@ -417,6 +417,7 @@
        case ThreadHandle::INVALID: thread_ = kNoThread; break;
      }
    }
+
    pthread_t thread_;  // Thread handle for pthread.
  };


Modified: branches/bleeding_edge/src/v8.cc
==============================================================================
--- branches/bleeding_edge/src/v8.cc    (original)
+++ branches/bleeding_edge/src/v8.cc    Thu Mar 26 17:24:49 2009
@@ -111,6 +111,8 @@
    Heap::TearDown();
    Logger::TearDown();

+  Debugger::TearDown();
+
    has_been_setup_ = false;
    has_been_disposed_ = true;
  }

Modified: branches/bleeding_edge/src/zone-inl.h
==============================================================================
--- branches/bleeding_edge/src/zone-inl.h       (original)
+++ branches/bleeding_edge/src/zone-inl.h       Thu Mar 26 17:24:49 2009
@@ -50,6 +50,12 @@
  }


+template <typename T>
+T* Zone::NewArray(int length) {
+  return static_cast<T*>(Zone::New(length * sizeof(T)));
+}
+
+
  bool Zone::excess_allocation() {
    return segment_bytes_allocated_ > zone_excess_limit_;
  }

Modified: branches/bleeding_edge/src/zone.h
==============================================================================
--- branches/bleeding_edge/src/zone.h   (original)
+++ branches/bleeding_edge/src/zone.h   Thu Mar 26 17:24:49 2009
@@ -58,6 +58,9 @@
    // allocating new segments of memory on demand using malloc().
    static inline void* New(int size);

+  template <typename T>
+  static inline T* NewArray(int length);
+
    // Delete all objects and free all memory allocated in the Zone.
    static void DeleteAll();


Modified: branches/bleeding_edge/test/cctest/cctest.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/cctest.cc        (original)
+++ branches/bleeding_edge/test/cctest/cctest.cc        Thu Mar 26 17:24:49 2009
@@ -30,6 +30,7 @@
  #include <cstring>
  #include <cstdio>
  #include "cctest.h"
+#include "debug.h"


  CcTest* CcTest::last_ = NULL;
@@ -120,5 +121,6 @@
    }
    if (print_run_count && tests_run != 1)
      printf("Ran %i tests.\n", tests_run);
+  v8::V8::Dispose();
    return 0;
  }

Modified: branches/bleeding_edge/test/cctest/test-api.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-api.cc      (original)
+++ branches/bleeding_edge/test/cctest/test-api.cc      Thu Mar 26 17:24:49 2009
@@ -154,7 +154,7 @@
  class RegisterThreadedTest {
   public:
    explicit RegisterThreadedTest(CcTest::TestFunction* callback)
-      : callback_(callback) {
+      : fuzzer_(NULL), callback_(callback) {
      prev_ = first_;
      first_ = this;
      count_++;
@@ -5098,6 +5098,10 @@

  void ApiTestFuzzer::TearDown() {
    fuzzing_ = false;
+  for (int i = 0; i < RegisterThreadedTest::count(); i++) {
+    ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_;
+    if (fuzzer != NULL) fuzzer->Join();
+  }
  }



Modified: branches/bleeding_edge/test/cctest/test-strings.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-strings.cc  (original)
+++ branches/bleeding_edge/test/cctest/test-strings.cc  Thu Mar 26 17:24:49  
2009
@@ -11,6 +11,7 @@

  #include "factory.h"
  #include "cctest.h"
+#include "zone-inl.h"

  unsigned int seed = 123;

@@ -48,6 +49,8 @@

  static void InitializeBuildingBlocks(
      Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS]) {
+  // A list of pointers that we don't have any interest in cleaning up.
+  // If they are reachable from a root then leak detection won't complain.
    for (int i = 0; i < NUMBER_OF_BUILDING_BLOCKS; i++) {
      int len = gen() % 16;
      if (len > 14) {
@@ -80,7 +83,7 @@
        }
        case 2: {
          class Resource: public v8::String::ExternalStringResource,
-                        public Malloced {
+                        public ZoneObject {
           public:
            explicit Resource(Vector<const uc16> string):  
data_(string.start()) {
              length_ = string.length();
@@ -92,7 +95,7 @@
            const uc16* data_;
            size_t length_;
          };
-        uc16* buf = NewArray<uc16>(len);
+        uc16* buf = Zone::NewArray<uc16>(len);
          for (int j = 0; j < len; j++) {
            buf[j] = gen() % 65536;
          }
@@ -212,6 +215,7 @@
    InitializeVM();
    v8::HandleScope scope;
    Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS];
+  ZoneScope zone(DELETE_ON_EXIT);
    InitializeBuildingBlocks(building_blocks);
    Handle<String> flat = ConstructBalanced(building_blocks);
    FlattenString(flat);
@@ -303,6 +307,7 @@
    InitializeVM();
    v8::HandleScope scope;
    Handle<String> building_blocks[NUMBER_OF_BUILDING_BLOCKS];
+  ZoneScope zone(DELETE_ON_EXIT);
    InitializeBuildingBlocks(building_blocks);

    seed = 42;

Modified: branches/bleeding_edge/test/message/testcfg.py
==============================================================================
--- branches/bleeding_edge/test/message/testcfg.py      (original)
+++ branches/bleeding_edge/test/message/testcfg.py      Thu Mar 26 17:24:49 2009
@@ -41,6 +41,11 @@
      self.config = config
      self.mode = mode

+  def IgnoreLine(self, str):
+    """Ignore empty lines and valgrind output."""
+    if not str: return True
+    else: return str.startswith('==') or str.startswith('**')
+
    def IsFailureOutput(self, output):
      f = file(self.expected)
      # Skip initial '#' comment and spaces
@@ -58,7 +63,8 @@
        pattern = '^%s$' % pattern
        patterns.append(pattern)
      # Compare actual output with the expected
-    outlines = [ s for s in output.stdout.split('\n') if s ]
+    raw_lines = output.stdout.split('\n')
+    outlines = [ s for s in raw_lines if not self.IgnoreLine(s) ]
      if len(outlines) != len(patterns):
        return True
      for i in xrange(len(patterns)):

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to