Version 1.2.5.

Fixed bug in initial boundary check for Boyer-Moore text search (issue 349).

Fixed compilation issues with MinGW and gcc 4.3+ and added support for armv7 and cortex-a8 architectures.  Patches by Lei Zhang and Craig Schlenter.

Added a script cache to the debugger.

Optimized compilation performance by improving internal data structures and avoiding expensive property load optimizations for code that's infrequently executed.

Exposed the calling JavaScript context through the static API function Context::GetCalling().


git-svn-id: http://v8.googlecode.com/svn/trunk@2050 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/debug.h b/src/debug.h
index 35336cb..3f90fa6 100644
--- a/src/debug.h
+++ b/src/debug.h
@@ -33,6 +33,7 @@
 #include "debug-agent.h"
 #include "execution.h"
 #include "factory.h"
+#include "hashmap.h"
 #include "platform.h"
 #include "string-stream.h"
 #include "v8threads.h"
@@ -40,7 +41,8 @@
 #ifdef ENABLE_DEBUGGER_SUPPORT
 #include "../include/v8-debug.h"
 
-namespace v8 { namespace internal {
+namespace v8 {
+namespace internal {
 
 
 // Forward declarations.
@@ -144,6 +146,42 @@
 };
 
 
+// Cache of all script objects in the heap. When a script is added a weak handle
+// to it is created and that weak handle is stored in the cache. The weak handle
+// callback takes care of removing the script from the cache. The key used in
+// the cache is the script id.
+class ScriptCache : private HashMap {
+ public:
+  ScriptCache() : HashMap(ScriptMatch), collected_scripts_(10) {}
+  virtual ~ScriptCache() { Clear(); }
+
+  // Add script to the cache.
+  void Add(Handle<Script> script);
+
+  // Return the scripts in the cache.
+  Handle<FixedArray> GetScripts();
+
+  // Generate debugger events for collected scripts.
+  void ProcessCollectedScripts();
+
+ private:
+  // Calculate the hash value from the key (script id).
+  static uint32_t Hash(int key) { return ComputeIntegerHash(key); }
+
+  // Scripts match if their keys (script id) match.
+  static bool ScriptMatch(void* key1, void* key2) { return key1 == key2; }
+
+  // Clear the cache releasing all the weak handles.
+  void Clear();
+
+  // Weak handle callback for scripts in the cache.
+  static void HandleWeakScript(v8::Persistent<v8::Value> obj, void* data);
+
+  // List used during GC to temporarily store id's of collected scripts.
+  List<int> collected_scripts_;
+};
+
+
 // Linked list holding debug info objects. The debug info objects are kept as
 // weak handles to avoid a debug info object to keep a function alive.
 class DebugInfoListNode {
@@ -230,9 +268,6 @@
   }
   static int break_id() { return thread_local_.break_id_; }
 
-
-
-
   static bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
   static void HandleStepIn(Handle<JSFunction> function,
                            Address fp,
@@ -307,6 +342,15 @@
   // Mirror cache handling.
   static void ClearMirrorCache();
 
+  // Script cache handling.
+  static void CreateScriptCache();
+  static void DestroyScriptCache();
+  static void AddScriptToScriptCache(Handle<Script> script);
+  static Handle<FixedArray> GetLoadedScripts();
+
+  // Garbage collection notifications.
+  static void AfterGarbageCollection();
+
   // Code generation assumptions.
   static const int kIa32CallInstructionLength = 5;
   static const int kIa32JSReturnSequenceLength = 6;
@@ -343,6 +387,11 @@
 
   // Boolean state indicating whether any break points are set.
   static bool has_break_points_;
+
+  // Cache of all scripts in the heap.
+  static ScriptCache* script_cache_;
+
+  // List of active debug info objects.
   static DebugInfoListNode* debug_info_list_;
 
   static bool disable_break_;
@@ -532,12 +581,15 @@
   static Handle<Object> MakeCompileEvent(Handle<Script> script,
                                          bool before,
                                          bool* caught_exception);
+  static Handle<Object> MakeScriptCollectedEvent(int id,
+                                                 bool* caught_exception);
   static void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
   static void OnException(Handle<Object> exception, bool uncaught);
   static void OnBeforeCompile(Handle<Script> script);
   static void OnAfterCompile(Handle<Script> script,
                            Handle<JSFunction> fun);
   static void OnNewFunction(Handle<JSFunction> fun);
+  static void OnScriptCollected(int id);
   static void ProcessDebugEvent(v8::DebugEvent event,
                                 Handle<JSObject> event_data,
                                 bool auto_continue);
@@ -578,7 +630,7 @@
     ScopedLock with(debugger_access_);
 
     // Check whether the message handler was been cleared.
-    if (message_handler_cleared_) {
+    if (debugger_unload_pending_) {
       UnloadDebugger();
     }
 
@@ -595,6 +647,7 @@
 
  private:
   static bool IsDebuggerActive();
+  static void ListenersChanged();
 
   static Mutex* debugger_access_;  // Mutex guarding debugger variables.
   static Handle<Object> event_listener_;  // Global handle to listener.
@@ -603,7 +656,7 @@
   static bool is_loading_debugger_;  // Are we loading the debugger?
   static bool never_unload_debugger_;  // Can we unload the debugger?
   static v8::Debug::MessageHandler2 message_handler_;
-  static bool message_handler_cleared_;  // Was message handler cleared?
+  static bool debugger_unload_pending_;  // Was message handler cleared?
   static v8::Debug::HostDispatchHandler host_dispatch_handler_;
   static int host_dispatch_micros_;
 
@@ -670,8 +723,15 @@
       StackGuard::DebugCommand();
     }
 
-    // If leaving the debugger with the debugger no longer active unload it.
     if (prev_ == NULL) {
+      // Clear mirror cache when leaving the debugger. Skip this if there is a
+      // pending exception as clearing the mirror cache calls back into
+      // JavaScript. This can happen if the v8::Debug::Call is used in which
+      // case the exception should end up in the calling code.
+      if (!Top::has_pending_exception()) {
+        Debug::ClearMirrorCache();
+      }
+      // If leaving the debugger with the debugger no longer active unload it.
       if (!Debugger::IsDebuggerActive()) {
         Debugger::UnloadDebugger();
       }