CPU profiler: add secure profiles by filtering out functions using security tokens.

As several pages can run in a single V8 instance, it is possible to
have functions from different security contexts intermixed in a single
CPU profile.  To avoid exposing function names from one page to
another, filtering is introduced.

The basic idea is that instead of capturing return addresses from
stack, we're now capturing JSFunction addresses (as we anyway work
only with JS stack frames.)  Each JSFunction can reach out for
context's security token. When providing a profile to a page, the
profile is filtered using the security token of caller page. Any
functions with different security tokens are filtered out (yes, we
only do fast path check for now) and their ticks are attributed to
their parents.

Review URL: http://codereview.chromium.org/2083005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4673 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 73b2fc29
...@@ -139,6 +139,15 @@ class V8EXPORT CpuProfile { ...@@ -139,6 +139,15 @@ class V8EXPORT CpuProfile {
*/ */
class V8EXPORT CpuProfiler { class V8EXPORT CpuProfiler {
public: public:
/**
* A note on security tokens usage. As scripts from different
* origins can run inside a single V8 instance, it is possible to
* have functions from different security contexts intermixed in a
* single CPU profile. To avoid exposing function names belonging to
* other contexts, filtering by security token is performed while
* obtaining profiling results.
*/
/** /**
* Returns the number of profiles collected (doesn't include * Returns the number of profiles collected (doesn't include
* profiles that are being collected at the moment of call.) * profiles that are being collected at the moment of call.)
...@@ -146,16 +155,22 @@ class V8EXPORT CpuProfiler { ...@@ -146,16 +155,22 @@ class V8EXPORT CpuProfiler {
static int GetProfilesCount(); static int GetProfilesCount();
/** Returns a profile by index. */ /** Returns a profile by index. */
static const CpuProfile* GetProfile(int index); static const CpuProfile* GetProfile(
int index,
Handle<Value> security_token = Handle<Value>());
/** Returns a profile by uid. */ /** Returns a profile by uid. */
static const CpuProfile* FindProfile(unsigned uid); static const CpuProfile* FindProfile(
unsigned uid,
Handle<Value> security_token = Handle<Value>());
/** /**
* Starts collecting CPU profile. Title may be an empty string. It * Starts collecting CPU profile. Title may be an empty string. It
* is allowed to have several profiles being collected at * is allowed to have several profiles being collected at
* once. Attempts to start collecting several profiles with the same * once. Attempts to start collecting several profiles with the same
* title are silently ignored. * title are silently ignored. While collecting a profile, functions
* from all security contexts are included in it. The token-based
* filtering is only performed when querying for a profile.
*/ */
static void StartProfiling(Handle<String> title); static void StartProfiling(Handle<String> title);
...@@ -163,7 +178,9 @@ class V8EXPORT CpuProfiler { ...@@ -163,7 +178,9 @@ class V8EXPORT CpuProfiler {
* Stops collecting CPU profile with a given title and returns it. * Stops collecting CPU profile with a given title and returns it.
* If the title given is empty, finishes the last profile started. * If the title given is empty, finishes the last profile started.
*/ */
static const CpuProfile* StopProfiling(Handle<String> title); static const CpuProfile* StopProfiling(
Handle<String> title,
Handle<Value> security_token = Handle<Value>());
}; };
......
...@@ -4250,15 +4250,23 @@ int CpuProfiler::GetProfilesCount() { ...@@ -4250,15 +4250,23 @@ int CpuProfiler::GetProfilesCount() {
} }
const CpuProfile* CpuProfiler::GetProfile(int index) { const CpuProfile* CpuProfiler::GetProfile(int index,
Handle<Value> security_token) {
IsDeadCheck("v8::CpuProfiler::GetProfile"); IsDeadCheck("v8::CpuProfiler::GetProfile");
return reinterpret_cast<const CpuProfile*>(i::CpuProfiler::GetProfile(index)); return reinterpret_cast<const CpuProfile*>(
i::CpuProfiler::GetProfile(
security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
index));
} }
const CpuProfile* CpuProfiler::FindProfile(unsigned uid) { const CpuProfile* CpuProfiler::FindProfile(unsigned uid,
Handle<Value> security_token) {
IsDeadCheck("v8::CpuProfiler::FindProfile"); IsDeadCheck("v8::CpuProfiler::FindProfile");
return reinterpret_cast<const CpuProfile*>(i::CpuProfiler::FindProfile(uid)); return reinterpret_cast<const CpuProfile*>(
i::CpuProfiler::FindProfile(
security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
uid));
} }
...@@ -4268,10 +4276,13 @@ void CpuProfiler::StartProfiling(Handle<String> title) { ...@@ -4268,10 +4276,13 @@ void CpuProfiler::StartProfiling(Handle<String> title) {
} }
const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title) { const CpuProfile* CpuProfiler::StopProfiling(Handle<String> title,
Handle<Value> security_token) {
IsDeadCheck("v8::CpuProfiler::StopProfiling"); IsDeadCheck("v8::CpuProfiler::StopProfiling");
return reinterpret_cast<const CpuProfile*>( return reinterpret_cast<const CpuProfile*>(
i::CpuProfiler::StopProfiling(*Utils::OpenHandle(*title))); i::CpuProfiler::StopProfiling(
security_token.IsEmpty() ? NULL : *Utils::OpenHandle(*security_token),
*Utils::OpenHandle(*title)));
} }
#endif // ENABLE_LOGGING_AND_PROFILING #endif // ENABLE_LOGGING_AND_PROFILING
......
...@@ -54,7 +54,7 @@ void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) { ...@@ -54,7 +54,7 @@ void CodeDeleteEventRecord::UpdateCodeMap(CodeMap* code_map) {
void CodeAliasEventRecord::UpdateCodeMap(CodeMap* code_map) { void CodeAliasEventRecord::UpdateCodeMap(CodeMap* code_map) {
code_map->AddAlias(alias, start); code_map->AddAlias(start, entry, code_start);
} }
......
...@@ -141,13 +141,15 @@ void ProfilerEventsProcessor::CodeDeleteEvent(Address from) { ...@@ -141,13 +141,15 @@ void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
void ProfilerEventsProcessor::FunctionCreateEvent(Address alias, void ProfilerEventsProcessor::FunctionCreateEvent(Address alias,
Address start) { Address start,
int security_token_id) {
CodeEventsContainer evt_rec; CodeEventsContainer evt_rec;
CodeAliasEventRecord* rec = &evt_rec.CodeAliasEventRecord_; CodeAliasEventRecord* rec = &evt_rec.CodeAliasEventRecord_;
rec->type = CodeEventRecord::CODE_ALIAS; rec->type = CodeEventRecord::CODE_ALIAS;
rec->order = ++enqueue_order_; rec->order = ++enqueue_order_;
rec->alias = alias; rec->start = alias;
rec->start = start; rec->entry = generator_->NewCodeEntry(security_token_id);
rec->code_start = start;
events_buffer_.Enqueue(evt_rec); events_buffer_.Enqueue(evt_rec);
} }
...@@ -257,26 +259,30 @@ CpuProfile* CpuProfiler::StopProfiling(const char* title) { ...@@ -257,26 +259,30 @@ CpuProfile* CpuProfiler::StopProfiling(const char* title) {
} }
CpuProfile* CpuProfiler::StopProfiling(String* title) { CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
return is_profiling() ? singleton_->StopCollectingProfile(title) : NULL; return is_profiling() ?
singleton_->StopCollectingProfile(security_token, title) : NULL;
} }
int CpuProfiler::GetProfilesCount() { int CpuProfiler::GetProfilesCount() {
ASSERT(singleton_ != NULL); ASSERT(singleton_ != NULL);
return singleton_->profiles_->profiles()->length(); // The count of profiles doesn't depend on a security token.
return singleton_->profiles_->Profiles(CodeEntry::kNoSecurityToken)->length();
} }
CpuProfile* CpuProfiler::GetProfile(int index) { CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
ASSERT(singleton_ != NULL); ASSERT(singleton_ != NULL);
return singleton_->profiles_->profiles()->at(index); const int token = singleton_->token_enumerator_->GetTokenId(security_token);
return singleton_->profiles_->Profiles(token)->at(index);
} }
CpuProfile* CpuProfiler::FindProfile(unsigned uid) { CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) {
ASSERT(singleton_ != NULL); ASSERT(singleton_ != NULL);
return singleton_->profiles_->GetProfile(uid); const int token = singleton_->token_enumerator_->GetTokenId(security_token);
return singleton_->profiles_->GetProfile(token, uid);
} }
...@@ -348,8 +354,15 @@ void CpuProfiler::CodeDeleteEvent(Address from) { ...@@ -348,8 +354,15 @@ void CpuProfiler::CodeDeleteEvent(Address from) {
void CpuProfiler::FunctionCreateEvent(JSFunction* function) { void CpuProfiler::FunctionCreateEvent(JSFunction* function) {
int security_token_id = CodeEntry::kNoSecurityToken;
if (function->unchecked_context()->IsContext()) {
security_token_id = singleton_->token_enumerator_->GetTokenId(
function->context()->global_context()->security_token());
}
singleton_->processor_->FunctionCreateEvent( singleton_->processor_->FunctionCreateEvent(
function->address(), function->code()->address()); function->address(),
function->code()->address(),
security_token_id);
} }
...@@ -388,12 +401,14 @@ void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) { ...@@ -388,12 +401,14 @@ void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) {
CpuProfiler::CpuProfiler() CpuProfiler::CpuProfiler()
: profiles_(new CpuProfilesCollection()), : profiles_(new CpuProfilesCollection()),
next_profile_uid_(1), next_profile_uid_(1),
token_enumerator_(new TokenEnumerator()),
generator_(NULL), generator_(NULL),
processor_(NULL) { processor_(NULL) {
} }
CpuProfiler::~CpuProfiler() { CpuProfiler::~CpuProfiler() {
delete token_enumerator_;
delete profiles_; delete profiles_;
} }
...@@ -438,7 +453,9 @@ void CpuProfiler::StartProcessorIfNotStarted() { ...@@ -438,7 +453,9 @@ void CpuProfiler::StartProcessorIfNotStarted() {
CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) { CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
const double actual_sampling_rate = generator_->actual_sampling_rate(); const double actual_sampling_rate = generator_->actual_sampling_rate();
StopProcessorIfLastProfile(); StopProcessorIfLastProfile();
CpuProfile* result = profiles_->StopProfiling(title, actual_sampling_rate); CpuProfile* result = profiles_->StopProfiling(CodeEntry::kNoSecurityToken,
title,
actual_sampling_rate);
if (result != NULL) { if (result != NULL) {
result->Print(); result->Print();
} }
...@@ -446,10 +463,12 @@ CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) { ...@@ -446,10 +463,12 @@ CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
} }
CpuProfile* CpuProfiler::StopCollectingProfile(String* title) { CpuProfile* CpuProfiler::StopCollectingProfile(Object* security_token,
String* title) {
const double actual_sampling_rate = generator_->actual_sampling_rate(); const double actual_sampling_rate = generator_->actual_sampling_rate();
StopProcessorIfLastProfile(); StopProcessorIfLastProfile();
return profiles_->StopProfiling(title, actual_sampling_rate); int token = token_enumerator_->GetTokenId(security_token);
return profiles_->StopProfiling(token, title, actual_sampling_rate);
} }
......
...@@ -41,7 +41,7 @@ class CodeMap; ...@@ -41,7 +41,7 @@ class CodeMap;
class CpuProfile; class CpuProfile;
class CpuProfilesCollection; class CpuProfilesCollection;
class ProfileGenerator; class ProfileGenerator;
class TokenEnumerator;
#define CODE_EVENTS_TYPE_LIST(V) \ #define CODE_EVENTS_TYPE_LIST(V) \
V(CODE_CREATION, CodeCreateEventRecord) \ V(CODE_CREATION, CodeCreateEventRecord) \
...@@ -94,8 +94,9 @@ class CodeDeleteEventRecord : public CodeEventRecord { ...@@ -94,8 +94,9 @@ class CodeDeleteEventRecord : public CodeEventRecord {
class CodeAliasEventRecord : public CodeEventRecord { class CodeAliasEventRecord : public CodeEventRecord {
public: public:
Address alias;
Address start; Address start;
CodeEntry* entry;
Address code_start;
INLINE(void UpdateCodeMap(CodeMap* code_map)); INLINE(void UpdateCodeMap(CodeMap* code_map));
}; };
...@@ -151,7 +152,7 @@ class ProfilerEventsProcessor : public Thread { ...@@ -151,7 +152,7 @@ class ProfilerEventsProcessor : public Thread {
Address start, unsigned size); Address start, unsigned size);
void CodeMoveEvent(Address from, Address to); void CodeMoveEvent(Address from, Address to);
void CodeDeleteEvent(Address from); void CodeDeleteEvent(Address from);
void FunctionCreateEvent(Address alias, Address start); void FunctionCreateEvent(Address alias, Address start, int security_token_id);
void FunctionMoveEvent(Address from, Address to); void FunctionMoveEvent(Address from, Address to);
void FunctionDeleteEvent(Address from); void FunctionDeleteEvent(Address from);
void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag, void RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,
...@@ -212,10 +213,10 @@ class CpuProfiler { ...@@ -212,10 +213,10 @@ class CpuProfiler {
static void StartProfiling(const char* title); static void StartProfiling(const char* title);
static void StartProfiling(String* title); static void StartProfiling(String* title);
static CpuProfile* StopProfiling(const char* title); static CpuProfile* StopProfiling(const char* title);
static CpuProfile* StopProfiling(String* title); static CpuProfile* StopProfiling(Object* security_token, String* title);
static int GetProfilesCount(); static int GetProfilesCount();
static CpuProfile* GetProfile(int index); static CpuProfile* GetProfile(Object* security_token, int index);
static CpuProfile* FindProfile(unsigned uid); static CpuProfile* FindProfile(Object* security_token, unsigned uid);
// Invoked from stack sampler (thread or signal handler.) // Invoked from stack sampler (thread or signal handler.)
static TickSample* TickSampleEvent(); static TickSample* TickSampleEvent();
...@@ -252,11 +253,12 @@ class CpuProfiler { ...@@ -252,11 +253,12 @@ class CpuProfiler {
void StartCollectingProfile(String* title); void StartCollectingProfile(String* title);
void StartProcessorIfNotStarted(); void StartProcessorIfNotStarted();
CpuProfile* StopCollectingProfile(const char* title); CpuProfile* StopCollectingProfile(const char* title);
CpuProfile* StopCollectingProfile(String* title); CpuProfile* StopCollectingProfile(Object* security_token, String* title);
void StopProcessorIfLastProfile(); void StopProcessorIfLastProfile();
CpuProfilesCollection* profiles_; CpuProfilesCollection* profiles_;
unsigned next_profile_uid_; unsigned next_profile_uid_;
TokenEnumerator* token_enumerator_;
ProfileGenerator* generator_; ProfileGenerator* generator_;
ProfilerEventsProcessor* processor_; ProfilerEventsProcessor* processor_;
int saved_logging_nesting_; int saved_logging_nesting_;
......
...@@ -170,7 +170,7 @@ void StackTracer::Trace(TickSample* sample) { ...@@ -170,7 +170,7 @@ void StackTracer::Trace(TickSample* sample) {
SafeStackTraceFrameIterator it(sample->fp, sample->sp, SafeStackTraceFrameIterator it(sample->fp, sample->sp,
sample->sp, js_entry_sp); sample->sp, js_entry_sp);
while (!it.done() && i < TickSample::kMaxFramesCount) { while (!it.done() && i < TickSample::kMaxFramesCount) {
sample->stack[i++] = it.frame()->pc(); sample->stack[i++] = reinterpret_cast<Address>(it.frame()->function());
it.Advance(); it.Advance();
} }
sample->frames_count = i; sample->frames_count = i;
......
...@@ -35,17 +35,30 @@ ...@@ -35,17 +35,30 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
CodeEntry::CodeEntry(int security_token_id)
: call_uid_(0),
tag_(Logger::FUNCTION_TAG),
name_prefix_(kEmptyNamePrefix),
name_(""),
resource_name_(""),
line_number_(0),
security_token_id_(security_token_id) {
}
CodeEntry::CodeEntry(Logger::LogEventsAndTags tag, CodeEntry::CodeEntry(Logger::LogEventsAndTags tag,
const char* name_prefix, const char* name_prefix,
const char* name, const char* name,
const char* resource_name, const char* resource_name,
int line_number) int line_number,
int security_token_id)
: call_uid_(next_call_uid_++), : call_uid_(next_call_uid_++),
tag_(tag), tag_(tag),
name_prefix_(name_prefix), name_prefix_(name_prefix),
name_(name), name_(name),
resource_name_(resource_name), resource_name_(resource_name),
line_number_(line_number) { line_number_(line_number),
security_token_id_(security_token_id) {
} }
......
This diff is collapsed.
...@@ -35,14 +35,34 @@ ...@@ -35,14 +35,34 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class TokenEnumerator {
public:
TokenEnumerator();
~TokenEnumerator();
int GetTokenId(Object* token);
private:
static void TokenRemovedCallback(v8::Persistent<v8::Value> handle,
void* parameter);
void TokenRemoved(Object** token_location);
List<Object**> token_locations_;
List<bool> token_removed_;
friend class TokenEnumeratorTester;
};
class CodeEntry { class CodeEntry {
public: public:
explicit INLINE(CodeEntry(int security_token_id));
// CodeEntry doesn't own name strings, just references them. // CodeEntry doesn't own name strings, just references them.
INLINE(CodeEntry(Logger::LogEventsAndTags tag, INLINE(CodeEntry(Logger::LogEventsAndTags tag,
const char* name_prefix, const char* name_prefix,
const char* name, const char* name,
const char* resource_name, const char* resource_name,
int line_number)); int line_number,
int security_token_id));
INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); } INLINE(bool is_js_function() const) { return is_js_function_tag(tag_); }
INLINE(const char* name_prefix() const) { return name_prefix_; } INLINE(const char* name_prefix() const) { return name_prefix_; }
...@@ -51,18 +71,24 @@ class CodeEntry { ...@@ -51,18 +71,24 @@ class CodeEntry {
INLINE(const char* resource_name() const) { return resource_name_; } INLINE(const char* resource_name() const) { return resource_name_; }
INLINE(int line_number() const) { return line_number_; } INLINE(int line_number() const) { return line_number_; }
INLINE(unsigned call_uid() const) { return call_uid_; } INLINE(unsigned call_uid() const) { return call_uid_; }
INLINE(int security_token_id() const) { return security_token_id_; }
INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag)); INLINE(static bool is_js_function_tag(Logger::LogEventsAndTags tag));
void CopyData(const CodeEntry& source);
static const char* kEmptyNamePrefix; static const char* kEmptyNamePrefix;
static const int kNoSecurityToken = -1;
static const int kInheritsSecurityToken = -2;
private: private:
const unsigned call_uid_; unsigned call_uid_;
Logger::LogEventsAndTags tag_; Logger::LogEventsAndTags tag_;
const char* name_prefix_; const char* name_prefix_;
const char* name_; const char* name_;
const char* resource_name_; const char* resource_name_;
int line_number_; int line_number_;
int security_token_id_;
static unsigned next_call_uid_; static unsigned next_call_uid_;
...@@ -79,6 +105,7 @@ class ProfileNode { ...@@ -79,6 +105,7 @@ class ProfileNode {
ProfileNode* FindChild(CodeEntry* entry); ProfileNode* FindChild(CodeEntry* entry);
ProfileNode* FindOrAddChild(CodeEntry* entry); ProfileNode* FindOrAddChild(CodeEntry* entry);
INLINE(void IncrementSelfTicks()) { ++self_ticks_; } INLINE(void IncrementSelfTicks()) { ++self_ticks_; }
INLINE(void IncreaseSelfTicks(unsigned amount)) { self_ticks_ += amount; }
INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; } INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; }
INLINE(CodeEntry* entry() const) { return entry_; } INLINE(CodeEntry* entry() const) { return entry_; }
...@@ -119,6 +146,7 @@ class ProfileTree { ...@@ -119,6 +146,7 @@ class ProfileTree {
void AddPathFromEnd(const Vector<CodeEntry*>& path); void AddPathFromEnd(const Vector<CodeEntry*>& path);
void AddPathFromStart(const Vector<CodeEntry*>& path); void AddPathFromStart(const Vector<CodeEntry*>& path);
void CalculateTotalTicks(); void CalculateTotalTicks();
void FilteredClone(ProfileTree* src, int security_token_id);
double TicksToMillis(unsigned ticks) const { double TicksToMillis(unsigned ticks) const {
return ticks * ms_to_ticks_scale_; return ticks * ms_to_ticks_scale_;
...@@ -133,7 +161,7 @@ class ProfileTree { ...@@ -133,7 +161,7 @@ class ProfileTree {
private: private:
template <typename Callback> template <typename Callback>
void TraverseDepthFirstPostOrder(Callback* callback); void TraverseDepthFirst(Callback* callback);
CodeEntry root_entry_; CodeEntry root_entry_;
ProfileNode* root_; ProfileNode* root_;
...@@ -152,6 +180,7 @@ class CpuProfile { ...@@ -152,6 +180,7 @@ class CpuProfile {
void AddPath(const Vector<CodeEntry*>& path); void AddPath(const Vector<CodeEntry*>& path);
void CalculateTotalTicks(); void CalculateTotalTicks();
void SetActualSamplingRate(double actual_sampling_rate); void SetActualSamplingRate(double actual_sampling_rate);
CpuProfile* FilteredClone(int security_token_id);
INLINE(const char* title() const) { return title_; } INLINE(const char* title() const) { return title_; }
INLINE(unsigned uid() const) { return uid_; } INLINE(unsigned uid() const) { return uid_; }
...@@ -179,7 +208,7 @@ class CodeMap { ...@@ -179,7 +208,7 @@ class CodeMap {
INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size)); INLINE(void AddCode(Address addr, CodeEntry* entry, unsigned size));
INLINE(void MoveCode(Address from, Address to)); INLINE(void MoveCode(Address from, Address to));
INLINE(void DeleteCode(Address addr)); INLINE(void DeleteCode(Address addr));
void AddAlias(Address alias, Address addr); void AddAlias(Address start, CodeEntry* entry, Address code_start);
CodeEntry* FindEntry(Address addr); CodeEntry* FindEntry(Address addr);
void Print(); void Print();
...@@ -221,10 +250,14 @@ class CpuProfilesCollection { ...@@ -221,10 +250,14 @@ class CpuProfilesCollection {
bool StartProfiling(const char* title, unsigned uid); bool StartProfiling(const char* title, unsigned uid);
bool StartProfiling(String* title, unsigned uid); bool StartProfiling(String* title, unsigned uid);
CpuProfile* StopProfiling(const char* title, double actual_sampling_rate); CpuProfile* StopProfiling(int security_token_id,
CpuProfile* StopProfiling(String* title, double actual_sampling_rate); const char* title,
INLINE(List<CpuProfile*>* profiles()) { return &profiles_; } double actual_sampling_rate);
CpuProfile* GetProfile(unsigned uid); CpuProfile* StopProfiling(int security_token_id,
String* title,
double actual_sampling_rate);
List<CpuProfile*>* Profiles(int security_token_id);
CpuProfile* GetProfile(int security_token_id, unsigned uid);
inline bool is_last_profile(); inline bool is_last_profile();
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
...@@ -233,6 +266,7 @@ class CpuProfilesCollection { ...@@ -233,6 +266,7 @@ class CpuProfilesCollection {
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag,
const char* name_prefix, String* name); const char* name_prefix, String* name);
CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count); CodeEntry* NewCodeEntry(Logger::LogEventsAndTags tag, int args_count);
CodeEntry* NewCodeEntry(int security_token_id);
// Called from profile generator thread. // Called from profile generator thread.
void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path); void AddPathToCurrentProfiles(const Vector<CodeEntry*>& path);
...@@ -242,13 +276,15 @@ class CpuProfilesCollection { ...@@ -242,13 +276,15 @@ class CpuProfilesCollection {
INLINE(const char* GetFunctionName(const char* name)); INLINE(const char* GetFunctionName(const char* name));
const char* GetName(String* name); const char* GetName(String* name);
const char* GetName(int args_count); const char* GetName(int args_count);
List<CpuProfile*>* GetProfilesList(int security_token_id);
int TokenToIndex(int security_token_id);
INLINE(static bool StringsMatch(void* key1, void* key2)) { INLINE(static bool StringsMatch(void* key1, void* key2)) {
return strcmp(reinterpret_cast<char*>(key1), return strcmp(reinterpret_cast<char*>(key1),
reinterpret_cast<char*>(key2)) == 0; reinterpret_cast<char*>(key2)) == 0;
} }
INLINE(static bool CpuProfilesMatch(void* key1, void* key2)) { INLINE(static bool UidsMatch(void* key1, void* key2)) {
return key1 == key2; return key1 == key2;
} }
...@@ -257,8 +293,8 @@ class CpuProfilesCollection { ...@@ -257,8 +293,8 @@ class CpuProfilesCollection {
// args_count -> char* // args_count -> char*
List<char*> args_count_names_; List<char*> args_count_names_;
List<CodeEntry*> code_entries_; List<CodeEntry*> code_entries_;
List<CpuProfile*> profiles_; List<List<CpuProfile*>* > profiles_by_token_;
// uid -> CpuProfile* // uid -> index
HashMap profiles_uids_; HashMap profiles_uids_;
// Accessed by VM thread and profile generator thread. // Accessed by VM thread and profile generator thread.
...@@ -332,6 +368,10 @@ class ProfileGenerator { ...@@ -332,6 +368,10 @@ class ProfileGenerator {
return profiles_->NewCodeEntry(tag, args_count); return profiles_->NewCodeEntry(tag, args_count);
} }
INLINE(CodeEntry* NewCodeEntry(int security_token_id)) {
return profiles_->NewCodeEntry(security_token_id);
}
void RecordTickSample(const TickSample& sample); void RecordTickSample(const TickSample& sample);
INLINE(CodeMap* code_map()) { return &code_map_; } INLINE(CodeMap* code_map()) { return &code_map_; }
......
...@@ -114,7 +114,8 @@ TEST(CodeEvents) { ...@@ -114,7 +114,8 @@ TEST(CodeEvents) {
processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500)); processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10); processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
processor.CodeDeleteEvent(ToAddress(0x1600)); processor.CodeDeleteEvent(ToAddress(0x1600));
processor.FunctionCreateEvent(ToAddress(0x1700), ToAddress(0x1000)); processor.FunctionCreateEvent(ToAddress(0x1700), ToAddress(0x1000),
CodeEntry::kNoSecurityToken);
// Enqueue a tick event to enable code events processing. // Enqueue a tick event to enable code events processing.
EnqueueTickSampleEvent(&processor, ToAddress(0x1000)); EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
...@@ -176,7 +177,8 @@ TEST(TickEvents) { ...@@ -176,7 +177,8 @@ TEST(TickEvents) {
processor.Stop(); processor.Stop();
processor.Join(); processor.Join();
CpuProfile* profile = profiles.StopProfiling("", 1); CpuProfile* profile =
profiles.StopProfiling(CodeEntry::kNoSecurityToken, "", 1);
CHECK_NE(NULL, profile); CHECK_NE(NULL, profile);
// Check call trees. // Check call trees.
......
...@@ -66,28 +66,6 @@ static void DoTraceHideCEntryFPAddress(Address fp) { ...@@ -66,28 +66,6 @@ static void DoTraceHideCEntryFPAddress(Address fp) {
} }
static void CheckRetAddrIsInFunction(const char* func_name,
Address ret_addr,
Address func_start_addr,
unsigned int func_len) {
printf("CheckRetAddrIsInFunction \"%s\": %p %p %p\n",
func_name, func_start_addr, ret_addr, func_start_addr + func_len);
CHECK_GE(ret_addr, func_start_addr);
CHECK_GE(func_start_addr + func_len, ret_addr);
}
static void CheckRetAddrIsInJSFunction(const char* func_name,
Address ret_addr,
Handle<JSFunction> func) {
v8::internal::Code* func_code = func->code();
CheckRetAddrIsInFunction(
func_name, ret_addr,
func_code->instruction_start(),
func_code->ExecutableSize());
}
// --- T r a c e E x t e n s i o n --- // --- T r a c e E x t e n s i o n ---
class TraceExtension : public v8::Extension { class TraceExtension : public v8::Extension {
...@@ -209,11 +187,16 @@ static Handle<JSFunction> GetGlobalJSFunction(const char* name) { ...@@ -209,11 +187,16 @@ static Handle<JSFunction> GetGlobalJSFunction(const char* name) {
} }
static void CheckRetAddrIsInJSFunction(const char* func_name, static void CheckObjectIsJSFunction(const char* func_name,
Address ret_addr) { Address addr) {
CheckRetAddrIsInJSFunction(func_name, i::Object* obj = reinterpret_cast<i::Object*>(addr);
ret_addr, CHECK(obj->IsJSFunction());
GetGlobalJSFunction(func_name)); CHECK(JSFunction::cast(obj)->shared()->name()->IsString());
i::SmartPointer<char> found_name =
i::String::cast(
JSFunction::cast(
obj)->shared()->name())->ToCString();
CHECK_EQ(func_name, *found_name);
} }
...@@ -272,6 +255,7 @@ static void CreateTraceCallerFunction(const char* func_name, ...@@ -272,6 +255,7 @@ static void CreateTraceCallerFunction(const char* func_name,
Handle<JSFunction> func = CompileFunction(trace_call_buf.start()); Handle<JSFunction> func = CompileFunction(trace_call_buf.start());
CHECK(!func.is_null()); CHECK(!func.is_null());
i::FLAG_allow_natives_syntax = allow_natives_syntax; i::FLAG_allow_natives_syntax = allow_natives_syntax;
func->shared()->set_name(*NewString(func_name));
#ifdef DEBUG #ifdef DEBUG
v8::internal::Code* func_code = func->code(); v8::internal::Code* func_code = func->code();
...@@ -313,10 +297,8 @@ TEST(CFromJSStackTrace) { ...@@ -313,10 +297,8 @@ TEST(CFromJSStackTrace) {
// StackTracer::Trace // StackTracer::Trace
CHECK_GT(sample.frames_count, 1); CHECK_GT(sample.frames_count, 1);
// Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
CheckRetAddrIsInJSFunction("JSFuncDoTrace", CheckObjectIsJSFunction("JSFuncDoTrace", sample.stack[0]);
sample.stack[0]); CheckObjectIsJSFunction("JSTrace", sample.stack[1]);
CheckRetAddrIsInJSFunction("JSTrace",
sample.stack[1]);
} }
...@@ -359,10 +341,8 @@ TEST(PureJSStackTrace) { ...@@ -359,10 +341,8 @@ TEST(PureJSStackTrace) {
sample.function); sample.function);
CHECK_GT(sample.frames_count, 1); CHECK_GT(sample.frames_count, 1);
// Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
CheckRetAddrIsInJSFunction("JSTrace", CheckObjectIsJSFunction("JSTrace", sample.stack[0]);
sample.stack[0]); CheckObjectIsJSFunction("OuterJSTrace", sample.stack[1]);
CheckRetAddrIsInJSFunction("OuterJSTrace",
sample.stack[1]);
} }
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment