Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(153)

Unified Diff: src/debug.cc

Issue 115462: Add a script cache to the debugger... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« src/debug.h ('K') | « src/debug.h ('k') | src/debug-delay.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/debug.cc
===================================================================
--- src/debug.cc (revision 1984)
+++ src/debug.cc (working copy)
@@ -425,6 +425,7 @@
bool Debug::has_break_points_ = false;
+ScriptCache* Debug::script_cache_ = NULL;
DebugInfoListNode* Debug::debug_info_list_ = NULL;
@@ -486,6 +487,99 @@
Code* Debug::debug_break_return_ = NULL;
+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;
+ }
+
+ // 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();
+}
+
+
+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;
+}
+
+
+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());
+
+ HandleScope scope;
Mads Ager (chromium) 2009/05/18 12:57:00 Why do you need to create this handle to the scrip
Søren Thygesen Gjesse 2009/05/18 13:13:17 I don't - unused code.
+ Handle<Script> script(location);
+
+ // 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();
+}
+
+
+void Debug::Setup(bool create_heap_objects) {
+ ThreadInit();
+ if (create_heap_objects) {
+ // Get code to handle entry to debug break on return.
+ debug_break_return_entry_ =
+ Builtins::builtin(Builtins::Return_DebugBreakEntry);
+ ASSERT(debug_break_return_entry_->IsCode());
+
+ // Get code to handle debug break on return.
+ debug_break_return_ =
+ Builtins::builtin(Builtins::Return_DebugBreak);
+ ASSERT(debug_break_return_->IsCode());
+ }
+}
+
+
void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
RemoveDebugInfo(node->debug_info());
@@ -512,22 +606,6 @@
}
-void Debug::Setup(bool create_heap_objects) {
- ThreadInit();
- if (create_heap_objects) {
- // Get code to handle entry to debug break on return.
- debug_break_return_entry_ =
- Builtins::builtin(Builtins::Return_DebugBreakEntry);
- ASSERT(debug_break_return_entry_->IsCode());
-
- // Get code to handle debug break on return.
- debug_break_return_ =
- Builtins::builtin(Builtins::Return_DebugBreak);
- ASSERT(debug_break_return_->IsCode());
- }
-}
-
-
bool Debug::CompileDebuggerScript(int index) {
HandleScope scope;
@@ -627,6 +705,7 @@
// Debugger loaded.
debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
+
return true;
}
@@ -637,6 +716,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 +1496,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 before
Mads Ager (chromium) 2009/05/18 12:57:00 before before -> before
Søren Thygesen Gjesse 2009/05/18 13:13:17 Done.
+ // 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 +1688,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 +1809,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 +1896,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 +1971,6 @@
}
}
}
-
- // Clear the mirror cache.
- Debug::ClearMirrorCache();
}
@@ -1798,6 +2010,9 @@
case v8::AfterCompile:
sendEventMessage = true;
break;
+ case v8::ScriptCollected:
+ sendEventMessage = true;
+ break;
case v8::NewFunction:
break;
default:
« src/debug.h ('K') | « src/debug.h ('k') | src/debug-delay.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698