}
-void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) {
- code_map->DeleteCode(start);
-}
-
-
void SharedFunctionInfoMoveEventRecord::UpdateCodeMap(CodeMap* code_map) {
code_map->MoveCode(from, to);
}
}
-void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
- CodeEventsContainer evt_rec;
- CodeDeleteEventRecord* rec = &evt_rec.CodeDeleteEventRecord_;
- rec->type = CodeEventRecord::CODE_DELETE;
- rec->order = ++enqueue_order_;
- rec->start = from;
- events_buffer_.Enqueue(evt_rec);
-}
-
-
void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from,
Address to) {
CodeEventsContainer evt_rec;
void CpuProfiler::CodeDeleteEvent(Address from) {
- Isolate::Current()->cpu_profiler()->processor_->CodeDeleteEvent(from);
}
#define CODE_EVENTS_TYPE_LIST(V) \
V(CODE_CREATION, CodeCreateEventRecord) \
V(CODE_MOVE, CodeMoveEventRecord) \
- V(CODE_DELETE, CodeDeleteEventRecord) \
V(SHARED_FUNC_MOVE, SharedFunctionInfoMoveEventRecord)
};
-class CodeDeleteEventRecord : public CodeEventRecord {
- public:
- Address start;
-
- INLINE(void UpdateCodeMap(CodeMap* code_map));
-};
-
-
class SharedFunctionInfoMoveEventRecord : public CodeEventRecord {
public:
Address from;
}
+void Logger::LogExistingFunction(Handle<SharedFunctionInfo> shared,
+ Handle<Code> code) {
+ Handle<String> func_name(shared->DebugName());
+ if (shared->script()->IsScript()) {
+ Handle<Script> script(Script::cast(shared->script()));
+ if (script->name()->IsString()) {
+ Handle<String> script_name(String::cast(script->name()));
+ int line_num = GetScriptLineNumber(script, shared->start_position());
+ if (line_num > 0) {
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+ *code, *shared,
+ *script_name, line_num + 1));
+ } else {
+ // Can't distinguish eval and script here, so always use Script.
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
+ *code, *shared, *script_name));
+ }
+ } else {
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
+ *code, *shared, *func_name));
+ }
+ } else if (shared->IsApiFunction()) {
+ // API function.
+ FunctionTemplateInfo* fun_data = shared->get_api_func_data();
+ Object* raw_call_data = fun_data->call_code();
+ if (!raw_call_data->IsUndefined()) {
+ CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
+ Object* callback_obj = call_data->callback();
+ Address entry_point = v8::ToCData<Address>(callback_obj);
+ PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
+ }
+ } else {
+ PROFILE(ISOLATE,
+ CodeCreateEvent(
+ Logger::LAZY_COMPILE_TAG, *code, *shared, *func_name));
+ }
+}
+
+
void Logger::LogCompiledFunctions() {
HandleScope scope;
const int compiled_funcs_count = EnumerateCompiledFunctions(NULL, NULL);
if (*code_objects[i] == Isolate::Current()->builtins()->builtin(
Builtins::kLazyCompile))
continue;
- Handle<SharedFunctionInfo> shared = sfis[i];
- Handle<String> func_name(shared->DebugName());
- if (shared->script()->IsScript()) {
- Handle<Script> script(Script::cast(shared->script()));
- if (script->name()->IsString()) {
- Handle<String> script_name(String::cast(script->name()));
- int line_num = GetScriptLineNumber(script, shared->start_position());
- if (line_num > 0) {
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code_objects[i], *shared,
- *script_name, line_num + 1));
- } else {
- // Can't distinguish eval and script here, so always use Script.
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::ToNativeByScript(Logger::SCRIPT_TAG, *script),
- *code_objects[i], *shared, *script_name));
- }
- } else {
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::ToNativeByScript(Logger::LAZY_COMPILE_TAG, *script),
- *code_objects[i], *shared, *func_name));
- }
- } else if (shared->IsApiFunction()) {
- // API function.
- FunctionTemplateInfo* fun_data = shared->get_api_func_data();
- Object* raw_call_data = fun_data->call_code();
- if (!raw_call_data->IsUndefined()) {
- CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data);
- Object* callback_obj = call_data->callback();
- Address entry_point = v8::ToCData<Address>(callback_obj);
- PROFILE(ISOLATE, CallbackEvent(*func_name, entry_point));
- }
- } else {
- PROFILE(ISOLATE,
- CodeCreateEvent(
- Logger::LAZY_COMPILE_TAG, *code_objects[i],
- *shared, *func_name));
- }
+ LogExistingFunction(sfis[i], code_objects[i]);
}
}
void ResumeProfiler();
bool IsProfilerPaused();
+ void LogExistingFunction(Handle<SharedFunctionInfo> shared,
+ Handle<Code> code);
// Logs all compiled functions found in the heap.
void LogCompiledFunctions();
// Logs all accessor callbacks found in the heap.
}
-void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
- CodeTree::Locator locator;
- tree_.Insert(addr, &locator);
- locator.set_value(CodeEntryInfo(entry, size));
-}
-
-
-void CodeMap::MoveCode(Address from, Address to) {
- tree_.Move(from, to);
-}
-
-void CodeMap::DeleteCode(Address addr) {
- tree_.Remove(addr);
-}
-
-
CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) {
switch (tag) {
case GC:
CodeMap::CodeEntryInfo(NULL, 0);
+void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
+ DeleteAllCoveredCode(addr, addr + size);
+ CodeTree::Locator locator;
+ tree_.Insert(addr, &locator);
+ locator.set_value(CodeEntryInfo(entry, size));
+}
+
+
+void CodeMap::DeleteAllCoveredCode(Address start, Address end) {
+ List<Address> to_delete;
+ Address addr = end - 1;
+ while (addr >= start) {
+ CodeTree::Locator locator;
+ if (!tree_.FindGreatestLessThan(addr, &locator)) break;
+ Address start2 = locator.key(), end2 = start2 + locator.value().size;
+ if (start2 < end && start < end2) to_delete.Add(start2);
+ addr = start2 - 1;
+ }
+ for (int i = 0; i < to_delete.length(); ++i) tree_.Remove(to_delete[i]);
+}
+
+
CodeEntry* CodeMap::FindEntry(Address addr) {
CodeTree::Locator locator;
if (tree_.FindGreatestLessThan(addr, &locator)) {
}
+void CodeMap::MoveCode(Address from, Address to) {
+ if (from == to) return;
+ CodeTree::Locator locator;
+ if (!tree_.Find(from, &locator)) return;
+ CodeEntryInfo entry = locator.value();
+ tree_.Remove(from);
+ AddCode(to, entry.entry, entry.size);
+}
+
+
void CodeMap::CodeTreePrinter::Call(
const Address& key, const CodeMap::CodeEntryInfo& value) {
OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
class CodeMap {
public:
CodeMap() : next_shared_id_(1) { }
- INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
- INLINE(void MoveCode(Address from, Address to));
- INLINE(void DeleteCode(Address addr));
+ void AddCode(Address addr, CodeEntry* entry, unsigned size);
+ void MoveCode(Address from, Address to);
CodeEntry* FindEntry(Address addr);
int GetSharedId(Address addr);
void Call(const Address& key, const CodeEntryInfo& value);
};
+ void DeleteAllCoveredCode(Address start, Address end);
+
// Fake CodeEntry pointer to distinguish shared function entries.
static CodeEntry* const kSharedFunctionCodeEntry;
// are guaranteed to be in old space.
target->set_literals(*literals, SKIP_WRITE_BARRIER);
target->set_next_function_link(isolate->heap()->undefined_value());
+
+ if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
+ isolate->logger()->LogExistingFunction(
+ shared, Handle<Code>(shared->code()));
+ }
}
target->set_context(*context);
processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt],
processor: this.processCodeMove },
- 'code-delete': { parsers: [parseInt],
- processor: this.processCodeDelete },
+ 'code-delete': null,
'sfi-move': { parsers: [parseInt, parseInt],
processor: this.processFunctionMove },
'shared-library': null,
this.profile.moveCode(from, to);
};
-LogProcessor.prototype.processCodeDelete = function(start) {
- this.profile.deleteCode(start);
-};
-
LogProcessor.prototype.processFunctionMove = function(from, to) {
this.profile.moveFunc(from, to);
};
"Script", "String", "RegExp", "Date", "Error"];
function entitiesEqual(entityA, entityB) {
- if (entityA === null && entityB !== null) return true;
- if (entityA !== null && entityB === null) return false;
+ if ((entityA === null && entityB !== null) ||
+ (entityA !== null && entityB === null)) return true;
return entityA.size === entityB.size && entityNamesEqual(entityA, entityB);
}
// find the same entries. We skip builtins during log parsing, but compiled
// functions traversal may erroneously recognize them as functions, so we are
// expecting more functions in traversal vs. logging.
+ // Since we don't track code deletions, logging can also report more entries
+ // than traversal.
while (l_pos < l_len && t_pos < t_len) {
var entryA = logging_entries[l_pos];
var entryB = traversal_entries[t_pos];
if (!entities_equal) equal = false;
comparison.push([entities_equal, address, entityA, entityB]);
}
- if (l_pos < l_len) equal = false;
- while (l_pos < l_len) {
- var entryA = logging_entries[l_pos++];
- comparison.push([false, entryA[0], entryA[1], null]);
- }
return [equal, comparison];
}
0x80);
processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
- processor.CodeDeleteEvent(ToAddress(0x1600));
+ processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10);
// Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
namespace {
+
class ScopedLoggerInitializer {
public:
explicit ScopedLoggerInitializer(bool prof_lazy)
typedef i::NativesCollection<i::TEST> TestSources;
-// Test that logging of code create / move / delete events
-// is equivalent to traversal of a resulting heap.
+
+// Test that logging of code create / move events is equivalent to traversal of
+// a resulting heap.
TEST(EquivalenceOfLoggingAndTraversal) {
// This test needs to be run on a "clean" V8 to ensure that snapshot log
// is loaded. This is always true when running using tools/test.py because
code_map.AddCode(ToAddress(0x1700), &entry2, 0x100);
CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1500)));
CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
- code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1800));
+ code_map.MoveCode(ToAddress(0x1500), ToAddress(0x1700)); // Deprecate bbb.
CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1500)));
- CHECK_EQ(&entry2, code_map.FindEntry(ToAddress(0x1700)));
- CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
- code_map.DeleteCode(ToAddress(0x1700));
+ CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1700)));
+ CodeEntry entry3(i::Logger::FUNCTION_TAG, "", "ccc", "", 0,
+ TokenEnumerator::kNoSecurityToken);
+ code_map.AddCode(ToAddress(0x1750), &entry3, 0x100);
CHECK_EQ(NULL, code_map.FindEntry(ToAddress(0x1700)));
- CHECK_EQ(&entry1, code_map.FindEntry(ToAddress(0x1800)));
+ CHECK_EQ(&entry3, code_map.FindEntry(ToAddress(0x1750)));
}
* @param {CodeMap.CodeEntry} codeEntry Code entry object.
*/
CodeMap.prototype.addCode = function(start, codeEntry) {
+ this.deleteAllCoveredNodes_(this.dynamics_, start, start + codeEntry.size);
this.dynamics_.insert(start, codeEntry);
};
*/
CodeMap.prototype.moveCode = function(from, to) {
var removedNode = this.dynamics_.remove(from);
+ this.deleteAllCoveredNodes_(this.dynamics_, to, to + removedNode.value.size);
this.dynamics_.insert(to, removedNode.value);
};
};
+/**
+ * @private
+ */
+CodeMap.prototype.deleteAllCoveredNodes_ = function(tree, start, end) {
+ var to_delete = [];
+ var addr = end - 1;
+ while (addr >= start) {
+ var node = tree.findGreatestLessThan(addr);
+ if (!node) break;
+ var start2 = node.key, end2 = start2 + node.value.size;
+ if (start2 < end && start < end2) to_delete.push(start2);
+ addr = start2 - 1;
+ }
+ for (var i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
+};
+
+
/**
* @private
*/