Author: [email protected]
Date: Mon May 18 06:14:37 2009
New Revision: 1988
Modified:
branches/bleeding_edge/include/v8-debug.h
branches/bleeding_edge/src/debug-delay.js
branches/bleeding_edge/src/debug.cc
branches/bleeding_edge/src/debug.h
branches/bleeding_edge/src/heap.cc
branches/bleeding_edge/src/objects-debug.cc
branches/bleeding_edge/src/objects.cc
branches/bleeding_edge/src/runtime.cc
branches/bleeding_edge/src/utils.cc
branches/bleeding_edge/src/utils.h
branches/bleeding_edge/test/cctest/test-debug.cc
branches/bleeding_edge/test/mjsunit/debug-references.js
Log:
Add a script cache to the debugger
When loaded scripts are requested this cache is filled with all the script
objects in the heap. Hereafter its content is kept in sync with the active
scripts in the heap through the notifications of new scripts compiled and
by using weak handles to get notified when a script is collected.
Through the tracking of collected scripts the debugger event
OnScriptCollected have been added to notify a debugger that a script
previously returned through the scripts command is no longer in use.
Make the ComputeIntegerHash globally available.
Moved clearing of the mirror cache to when debugger is really left.
Previously recursive invocations of the debugger cause the mirror cache to
be cleared causing handles to become either stale or reference other
objects.
Review URL: http://codereview.chromium.org/115462
Modified: branches/bleeding_edge/include/v8-debug.h
==============================================================================
--- branches/bleeding_edge/include/v8-debug.h (original)
+++ branches/bleeding_edge/include/v8-debug.h Mon May 18 06:14:37 2009
@@ -75,7 +75,8 @@
Exception = 2,
NewFunction = 3,
BeforeCompile = 4,
- AfterCompile = 5
+ AfterCompile = 5,
+ ScriptCollected = 6
};
Modified: branches/bleeding_edge/src/debug-delay.js
==============================================================================
--- branches/bleeding_edge/src/debug-delay.js (original)
+++ branches/bleeding_edge/src/debug-delay.js Mon May 18 06:14:37 2009
@@ -43,7 +43,8 @@
Exception: 2,
NewFunction: 3,
BeforeCompile: 4,
- AfterCompile: 5 };
+ AfterCompile: 5,
+ ScriptCollected: 6 };
// Types of exceptions that can be broken upon.
Debug.ExceptionBreak = { All : 0,
@@ -1013,6 +1014,37 @@
NewFunctionEvent.prototype.setBreakPoint = function(p) {
Debug.setBreakPoint(this.func, p || 0);
};
+
+
+function MakeScriptCollectedEvent(exec_state, id) {
+ return new ScriptCollectedEvent(exec_state, id);
+}
+
+
+function ScriptCollectedEvent(exec_state, id) {
+ this.exec_state_ = exec_state;
+ this.id_ = id;
+}
+
+
+ScriptCollectedEvent.prototype.id = function() {
+ return this.id_;
+};
+
+
+ScriptCollectedEvent.prototype.executionState = function() {
+ return this.exec_state_;
+};
+
+
+ScriptCollectedEvent.prototype.toJSONProtocol = function() {
+ var o = new ProtocolMessage();
+ o.running = true;
+ o.event = "scriptCollected";
+ o.body = {};
+ o.body.script = { id: this.id() };
+ return o.toJSONProtocol();
+}
function MakeScriptObject_(script, include_source) {
Modified: branches/bleeding_edge/src/debug.cc
==============================================================================
--- branches/bleeding_edge/src/debug.cc (original)
+++ branches/bleeding_edge/src/debug.cc Mon May 18 06:14:37 2009
@@ -425,6 +425,7 @@
bool Debug::has_break_points_ = false;
+ScriptCache* Debug::script_cache_ = NULL;
DebugInfoListNode* Debug::debug_info_list_ = NULL;
@@ -486,29 +487,77 @@
Code* Debug::debug_break_return_ = NULL;
-void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data)
{
- DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
- RemoveDebugInfo(node->debug_info());
-#ifdef DEBUG
- node = Debug::debug_info_list_;
- while (node != NULL) {
- ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
- node = node->next();
+void ScriptCache::Add(Handle<Script> script) {
+ // Create an entry in the hash map for the script.
+ int id = Smi::cast(script->id())->value();
+ HashMap::Entry* entry =
+ HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
+ if (entry->value != NULL) {
+ ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
+ return;
}
-#endif
+
+ // Globalize the script object, make it weak and use the location of the
+ // global handle as the value in the hash map.
+ Handle<Script> script_ =
+ Handle<Script>::cast((GlobalHandles::Create(*script)));
+ GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
+ this, ScriptCache::HandleWeakScript);
+ entry->value = script_.location();
}
-DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
- // Globalize the request debug info object and make it weak.
- debug_info_ =
Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
-
GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
- this, Debug::HandleWeakDebugInfo);
+Handle<FixedArray> ScriptCache::GetScripts() {
+ Handle<FixedArray> instances = Factory::NewFixedArray(occupancy());
+ int count = 0;
+ for (HashMap::Entry* entry = Start(); entry != NULL; entry =
Next(entry)) {
+ ASSERT(entry->value != NULL);
+ if (entry->value != NULL) {
+ instances->set(count, *reinterpret_cast<Script**>(entry->value));
+ count++;
+ }
+ }
+ return instances;
}
-DebugInfoListNode::~DebugInfoListNode() {
-
GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
+void ScriptCache::ProcessCollectedScripts() {
+ for (int i = 0; i < collected_scripts_.length(); i++) {
+ Debugger::OnScriptCollected(collected_scripts_[i]);
+ }
+ collected_scripts_.Clear();
+}
+
+
+void ScriptCache::Clear() {
+ // Iterate the script cache to get rid of all the weak handles.
+ for (HashMap::Entry* entry = Start(); entry != NULL; entry =
Next(entry)) {
+ ASSERT(entry != NULL);
+ Object** location = reinterpret_cast<Object**>(entry->value);
+ ASSERT((*location)->IsScript());
+ GlobalHandles::ClearWeakness(location);
+ GlobalHandles::Destroy(location);
+ }
+ // Clear the content of the hash map.
+ HashMap::Clear();
+}
+
+
+void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void*
data) {
+ ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
+ // Find the location of the global handle.
+ Script** location =
+ reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
+ ASSERT((*location)->IsScript());
+
+ // Remove the entry from the cache.
+ int id = Smi::cast((*location)->id())->value();
+ script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
+ script_cache->collected_scripts_.Add(id);
+
+ // Clear the weak handle.
+ obj.Dispose();
+ obj.Clear();
}
@@ -528,6 +577,32 @@
}
+void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data)
{
+ DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
+ RemoveDebugInfo(node->debug_info());
+#ifdef DEBUG
+ node = Debug::debug_info_list_;
+ while (node != NULL) {
+ ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
+ node = node->next();
+ }
+#endif
+}
+
+
+DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
+ // Globalize the request debug info object and make it weak.
+ debug_info_ =
Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
+
GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
+ this, Debug::HandleWeakDebugInfo);
+}
+
+
+DebugInfoListNode::~DebugInfoListNode() {
+
GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
+}
+
+
bool Debug::CompileDebuggerScript(int index) {
HandleScope scope;
@@ -627,6 +702,7 @@
// Debugger loaded.
debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
+
return true;
}
@@ -637,6 +713,9 @@
return;
}
+ // Clear the script cache.
+ DestroyScriptCache();
+
// Clear debugger context global handle.
GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
debug_context_ = Handle<Context>();
@@ -1414,6 +1493,94 @@
}
+// If an object given is an external string, check that the underlying
+// resource is accessible. For other kinds of objects, always return true.
+static bool IsExternalStringValid(Object* str) {
+ if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
+ return true;
+ }
+ if (String::cast(str)->IsAsciiRepresentation()) {
+ return ExternalAsciiString::cast(str)->resource() != NULL;
+ } else if (String::cast(str)->IsTwoByteRepresentation()) {
+ return ExternalTwoByteString::cast(str)->resource() != NULL;
+ } else {
+ return true;
+ }
+}
+
+
+void Debug::CreateScriptCache() {
+ HandleScope scope;
+
+ // Perform two GCs to get rid of all unreferenced scripts. The first GC
gets
+ // rid of all the cached script wrappers and the second gets rid of the
+ // scripts which is no longer referenced.
+ Heap::CollectAllGarbage();
+ Heap::CollectAllGarbage();
+
+ ASSERT(script_cache_ == NULL);
+ script_cache_ = new ScriptCache();
+
+ // Scan heap for Script objects.
+ int count = 0;
+ HeapIterator iterator;
+ while (iterator.has_next()) {
+ HeapObject* obj = iterator.next();
+ ASSERT(obj != NULL);
+ if (obj->IsScript() &&
IsExternalStringValid(Script::cast(obj)->source())) {
+ script_cache_->Add(Handle<Script>(Script::cast(obj)));
+ count++;
+ }
+ }
+}
+
+
+void Debug::DestroyScriptCache() {
+ // Get rid of the script cache if it was created.
+ if (script_cache_ != NULL) {
+ delete script_cache_;
+ script_cache_ = NULL;
+ }
+}
+
+
+void Debug::AddScriptToScriptCache(Handle<Script> script) {
+ if (script_cache_ != NULL) {
+ script_cache_->Add(script);
+ }
+}
+
+
+Handle<FixedArray> Debug::GetLoadedScripts() {
+ // Create and fill the script cache when the loaded scripts is requested
for
+ // the first time.
+ if (script_cache_ == NULL) {
+ CreateScriptCache();
+ }
+
+ // If the script cache is not active just return an empty array.
+ ASSERT(script_cache_ != NULL);
+ if (script_cache_ == NULL) {
+ Factory::NewFixedArray(0);
+ }
+
+ // Perform GC to get unreferenced scripts evicted from the cache before
+ // returning the content.
+ Heap::CollectAllGarbage();
+
+ // Get the scripts from the cache.
+ return script_cache_->GetScripts();
+}
+
+
+void Debug::AfterGarbageCollection() {
+ // Generate events for collected scripts.
+ if (script_cache_ != NULL) {
+ script_cache_->ProcessCollectedScripts();
+ }
+}
+
+
Mutex* Debugger::debugger_access_ = OS::CreateMutex();
Handle<Object> Debugger::event_listener_ = Handle<Object>();
Handle<Object> Debugger::event_listener_data_ = Handle<Object>();
@@ -1518,6 +1685,21 @@
}
+Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
+ bool* caught_exception) {
+ // Create the script collected event object.
+ Handle<Object> exec_state = MakeExecutionState(caught_exception);
+ Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
+ const int argc = 2;
+ Object** argv[argc] = { exec_state.location(), id_object.location() };
+
+ return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
+ argc,
+ argv,
+ caught_exception);
+}
+
+
void Debugger::OnException(Handle<Object> exception, bool uncaught) {
HandleScope scope;
@@ -1624,12 +1806,15 @@
void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction>
fun) {
HandleScope scope;
- // No compile events while compiling natives.
- if (compiling_natives()) return;
+ // Add the newly compiled script to the script cache.
+ Debug::AddScriptToScriptCache(script);
// No more to do if not debugging.
if (!IsDebuggerActive()) return;
+ // No compile events while compiling natives.
+ if (compiling_natives()) return;
+
// Store whether in debugger before entering debugger.
bool in_debugger = Debug::InDebugger();
@@ -1708,6 +1893,33 @@
}
+void Debugger::OnScriptCollected(int id) {
+ HandleScope scope;
+
+ // No more to do if not debugging.
+ if (!IsDebuggerActive()) return;
+ if (!Debugger::EventActive(v8::ScriptCollected)) return;
+
+ // Enter the debugger.
+ EnterDebugger debugger;
+ if (debugger.FailedToEnter()) return;
+
+ // Create the script collected state object.
+ bool caught_exception = false;
+ Handle<Object> event_data = MakeScriptCollectedEvent(id,
+ &caught_exception);
+ // Bail out and don't call debugger if exception.
+ if (caught_exception) {
+ return;
+ }
+
+ // Process debug event.
+ ProcessDebugEvent(v8::ScriptCollected,
+ Handle<JSObject>::cast(event_data),
+ true);
+}
+
+
void Debugger::ProcessDebugEvent(v8::DebugEvent event,
Handle<JSObject> event_data,
bool auto_continue) {
@@ -1756,9 +1968,6 @@
}
}
}
-
- // Clear the mirror cache.
- Debug::ClearMirrorCache();
}
@@ -1796,6 +2005,9 @@
case v8::BeforeCompile:
break;
case v8::AfterCompile:
+ sendEventMessage = true;
+ break;
+ case v8::ScriptCollected:
sendEventMessage = true;
break;
case v8::NewFunction:
Modified: branches/bleeding_edge/src/debug.h
==============================================================================
--- branches/bleeding_edge/src/debug.h (original)
+++ branches/bleeding_edge/src/debug.h Mon May 18 06:14:37 2009
@@ -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"
@@ -144,6 +145,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 +267,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 +341,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 +386,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 +580,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);
@@ -670,8 +721,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();
}
Modified: branches/bleeding_edge/src/heap.cc
==============================================================================
--- branches/bleeding_edge/src/heap.cc (original)
+++ branches/bleeding_edge/src/heap.cc Mon May 18 06:14:37 2009
@@ -283,6 +283,9 @@
#if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING)
ReportStatisticsAfterGC();
#endif
+#ifdef ENABLE_DEBUGGER_SUPPORT
+ Debug::AfterGarbageCollection();
+#endif
}
Modified: branches/bleeding_edge/src/objects-debug.cc
==============================================================================
--- branches/bleeding_edge/src/objects-debug.cc (original)
+++ branches/bleeding_edge/src/objects-debug.cc Mon May 18 06:14:37 2009
@@ -941,6 +941,8 @@
column_offset()->ShortPrint();
PrintF("\n - type: ");
type()->ShortPrint();
+ PrintF("\n - id: ");
+ id()->ShortPrint();
PrintF("\n");
}
Modified: branches/bleeding_edge/src/objects.cc
==============================================================================
--- branches/bleeding_edge/src/objects.cc (original)
+++ branches/bleeding_edge/src/objects.cc Mon May 18 06:14:37 2009
@@ -5936,20 +5936,6 @@
}
-// Thomas Wang, Integer Hash Functions.
-// http://www.concentric.net/~Ttwang/tech/inthash.htm
-static uint32_t ComputeIntegerHash(uint32_t key) {
- uint32_t hash = key;
- hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
- hash = hash ^ (hash >> 12);
- hash = hash + (hash << 2);
- hash = hash ^ (hash >> 4);
- hash = hash * 2057; // hash = (hash + (hash << 3)) + (hash << 11);
- hash = hash ^ (hash >> 16);
- return hash;
-}
-
-
// The NumberKey uses carries the uint32_t as key.
// This avoids allocation in HasProperty.
class NumberKey : public HashTableKey {
Modified: branches/bleeding_edge/src/runtime.cc
==============================================================================
--- branches/bleeding_edge/src/runtime.cc (original)
+++ branches/bleeding_edge/src/runtime.cc Mon May 18 06:14:37 2009
@@ -6638,67 +6638,15 @@
}
-// If an object given is an external string, check that the underlying
-// resource is accessible. For other kinds of objects, always return true.
-static bool IsExternalStringValid(Object* str) {
- if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
- return true;
- }
- if (String::cast(str)->IsAsciiRepresentation()) {
- return ExternalAsciiString::cast(str)->resource() != NULL;
- } else if (String::cast(str)->IsTwoByteRepresentation()) {
- return ExternalTwoByteString::cast(str)->resource() != NULL;
- } else {
- return true;
- }
-}
-
-
-// Helper function used by Runtime_DebugGetLoadedScripts below.
-static int DebugGetLoadedScripts(FixedArray* instances, int
instances_size) {
- NoHandleAllocation ha;
- AssertNoAllocation no_alloc;
-
- // Scan heap for Script objects.
- int count = 0;
- HeapIterator iterator;
- while (iterator.has_next()) {
- HeapObject* obj = iterator.next();
- ASSERT(obj != NULL);
- if (obj->IsScript() &&
IsExternalStringValid(Script::cast(obj)->source())) {
- if (instances != NULL && count < instances_size) {
- instances->set(count, obj);
- }
- count++;
- }
- }
-
- return count;
-}
-
-
static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
HandleScope scope;
ASSERT(args.length() == 0);
- // Perform two GCs to get rid of all unreferenced scripts. The first GC
gets
- // rid of all the cached script wrappers and the second gets rid of the
- // scripts which is no longer referenced.
- Heap::CollectAllGarbage();
- Heap::CollectAllGarbage();
-
- // Get the number of scripts.
- int count;
- count = DebugGetLoadedScripts(NULL, 0);
-
- // Allocate an array to hold the result.
- Handle<FixedArray> instances = Factory::NewFixedArray(count);
-
// Fill the script objects.
- count = DebugGetLoadedScripts(*instances, count);
+ Handle<FixedArray> instances = Debug::GetLoadedScripts();
// Convert the script objects to proper JS objects.
- for (int i = 0; i < count; i++) {
+ for (int i = 0; i < instances->length(); i++) {
Handle<Script> script =
Handle<Script>(Script::cast(instances->get(i)));
// Get the script wrapper in a local handle before calling
GetScriptWrapper,
// because using
Modified: branches/bleeding_edge/src/utils.cc
==============================================================================
--- branches/bleeding_edge/src/utils.cc (original)
+++ branches/bleeding_edge/src/utils.cc Mon May 18 06:14:37 2009
@@ -86,6 +86,20 @@
}
+// Thomas Wang, Integer Hash Functions.
+// http://www.concentric.net/~Ttwang/tech/inthash.htm
+uint32_t ComputeIntegerHash(uint32_t key) {
+ uint32_t hash = key;
+ hash = ~hash + (hash << 15); // hash = (hash << 15) - hash - 1;
+ hash = hash ^ (hash >> 12);
+ hash = hash + (hash << 2);
+ hash = hash ^ (hash >> 4);
+ hash = hash * 2057; // hash = (hash + (hash << 3)) + (hash << 11);
+ hash = hash ^ (hash >> 16);
+ return hash;
+}
+
+
void PrintF(const char* format, ...) {
va_list arguments;
va_start(arguments, format);
Modified: branches/bleeding_edge/src/utils.h
==============================================================================
--- branches/bleeding_edge/src/utils.h (original)
+++ branches/bleeding_edge/src/utils.h Mon May 18 06:14:37 2009
@@ -205,6 +205,12 @@
//
----------------------------------------------------------------------------
+// Hash function.
+
+uint32_t ComputeIntegerHash(uint32_t key);
+
+
+//
----------------------------------------------------------------------------
// I/O support.
// Our version of printf(). Avoids compilation errors that we get
Modified: branches/bleeding_edge/test/cctest/test-debug.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-debug.cc (original)
+++ branches/bleeding_edge/test/cctest/test-debug.cc Mon May 18 06:14:37
2009
@@ -4531,6 +4531,8 @@
TEST(DebugGetLoadedScripts) {
v8::HandleScope scope;
DebugLocalContext env;
+ env.ExposeDebug();
+
EmptyExternalStringResource source_ext_str;
v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
v8::Handle<v8::Script> evil_script = v8::Script::Compile(source);
@@ -4544,11 +4546,15 @@
i::FLAG_allow_natives_syntax = true;
CompileRun(
"var scripts = %DebugGetLoadedScripts();"
- "for (var i = 0; i < scripts.length; ++i) {"
- " scripts[i].line_ends;"
+ "var count = scripts.length;"
+ "for (var i = 0; i < count; ++i) {"
+ " scripts[i].line_ends;"
"}");
// Must not crash while accessing line_ends.
i::FLAG_allow_natives_syntax = allow_natives_syntax;
+
+ // Some scripts are retrieved - at least the number of native scripts.
+ CHECK_GT((*env)->Global()->Get(v8::String::New("count"))->Int32Value(),
8);
}
@@ -4685,4 +4691,49 @@
// Two times compile event and two times break event.
CHECK_GT(message_handler_hit_count, 4);
+}
+
+
+// Debug event listener which counts the script collected events.
+int script_collected_count = 0;
+static void DebugEventScriptCollectedEvent(v8::DebugEvent event,
+ v8::Handle<v8::Object>
exec_state,
+ v8::Handle<v8::Object>
event_data,
+ v8::Handle<v8::Value> data) {
+ // Count the number of breaks.
+ if (event == v8::ScriptCollected) {
+ script_collected_count++;
+ }
+}
+
+
+// Test that scripts collected are reported through the debug event
listener.
+TEST(ScriptCollectedEvent) {
+ break_point_hit_count = 0;
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ // Request the loaded scripte to initialize the debugger script cache.
+ Debug::GetLoadedScripts();
+
+ // Do garbage collection to ensure that only the script in this test
will be
+ // collected afterwards.
+ Heap::CollectAllGarbage();
+
+ script_collected_count = 0;
+ v8::Debug::SetDebugEventListener(DebugEventScriptCollectedEvent,
+ v8::Undefined());
+ {
+ v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
+ v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
+ }
+
+ // Do garbage collection to collect the script above which is no longer
+ // referenced.
+ Heap::CollectAllGarbage();
+
+ CHECK_EQ(2, script_collected_count);
+
+ v8::Debug::SetDebugEventListener(NULL);
+ CheckDebuggerUnloaded();
}
Modified: branches/bleeding_edge/test/mjsunit/debug-references.js
==============================================================================
--- branches/bleeding_edge/test/mjsunit/debug-references.js (original)
+++ branches/bleeding_edge/test/mjsunit/debug-references.js Mon May 18
06:14:37 2009
@@ -113,6 +113,6 @@
// Enter debugger causing the event listener to be called.
debugger;
-// Make sure that the debug event listener vas invoked.
+// Make sure that the debug event listener was invoked.
assertFalse(exception, "exception in listener")
assertTrue(listenerComplete, "listener did not run to completion");
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---