blob: e5b519401cb921da79745454fc3c6294fb926eb5 [file] [log] [blame]
ulan@chromium.org65a89c22012-02-14 11:46:07 +00001// Copyright 2012 the V8 project authors. All rights reserved.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000029
30#include "profile-generator-inl.h"
31
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000032#include "global-handles.h"
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000033#include "scopeinfo.h"
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000034#include "unicode.h"
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000035#include "zone-inl.h"
svenpanne@chromium.orgfb046332012-04-19 12:02:44 +000036#include "debug.h"
fschneider@chromium.org086aac62010-03-17 13:18:24 +000037
fschneider@chromium.org086aac62010-03-17 13:18:24 +000038namespace v8 {
39namespace internal {
40
41
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000042TokenEnumerator::TokenEnumerator()
43 : token_locations_(4),
44 token_removed_(4) {
45}
46
47
48TokenEnumerator::~TokenEnumerator() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000049 Isolate* isolate = Isolate::Current();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000050 for (int i = 0; i < token_locations_.length(); ++i) {
51 if (!token_removed_[i]) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000052 isolate->global_handles()->ClearWeakness(token_locations_[i]);
53 isolate->global_handles()->Destroy(token_locations_[i]);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000054 }
55 }
56}
57
58
59int TokenEnumerator::GetTokenId(Object* token) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000060 Isolate* isolate = Isolate::Current();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000061 if (token == NULL) return TokenEnumerator::kNoSecurityToken;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000062 for (int i = 0; i < token_locations_.length(); ++i) {
63 if (*token_locations_[i] == token && !token_removed_[i]) return i;
64 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 Handle<Object> handle = isolate->global_handles()->Create(token);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000066 // handle.location() points to a memory cell holding a pointer
67 // to a token object in the V8's heap.
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000068 isolate->global_handles()->MakeWeak(handle.location(),
69 this,
70 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000071 TokenRemovedCallback);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000072 token_locations_.Add(handle.location());
73 token_removed_.Add(false);
74 return token_locations_.length() - 1;
75}
76
77
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000078void TokenEnumerator::TokenRemovedCallback(v8::Isolate* isolate,
79 v8::Persistent<v8::Value> handle,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000080 void* parameter) {
81 reinterpret_cast<TokenEnumerator*>(parameter)->TokenRemoved(
82 Utils::OpenHandle(*handle).location());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +000083 handle.Dispose(isolate);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000084}
85
86
87void TokenEnumerator::TokenRemoved(Object** token_location) {
88 for (int i = 0; i < token_locations_.length(); ++i) {
89 if (token_locations_[i] == token_location && !token_removed_[i]) {
90 token_removed_[i] = true;
91 return;
92 }
93 }
94}
95
96
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000097StringsStorage::StringsStorage()
98 : names_(StringsMatch) {
99}
100
101
102StringsStorage::~StringsStorage() {
103 for (HashMap::Entry* p = names_.Start();
104 p != NULL;
105 p = names_.Next(p)) {
106 DeleteArray(reinterpret_cast<const char*>(p->value));
107 }
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000108}
109
110
111const char* StringsStorage::GetCopy(const char* src) {
112 int len = static_cast<int>(strlen(src));
113 Vector<char> dst = Vector<char>::New(len + 1);
114 OS::StrNCpy(dst, src, len);
115 dst[len] = '\0';
rossberg@chromium.orgfab14982012-01-05 15:02:15 +0000116 uint32_t hash =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000117 StringHasher::HashSequentialString(dst.start(), len, HEAP->HashSeed());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000118 return AddOrDisposeString(dst.start(), hash);
119}
120
121
122const char* StringsStorage::GetFormatted(const char* format, ...) {
123 va_list args;
124 va_start(args, format);
125 const char* result = GetVFormatted(format, args);
126 va_end(args);
127 return result;
128}
129
130
131const char* StringsStorage::AddOrDisposeString(char* str, uint32_t hash) {
132 HashMap::Entry* cache_entry = names_.Lookup(str, hash, true);
133 if (cache_entry->value == NULL) {
134 // New entry added.
135 cache_entry->value = str;
136 } else {
137 DeleteArray(str);
138 }
139 return reinterpret_cast<const char*>(cache_entry->value);
140}
141
142
143const char* StringsStorage::GetVFormatted(const char* format, va_list args) {
144 Vector<char> str = Vector<char>::New(1024);
145 int len = OS::VSNPrintF(str, format, args);
146 if (len == -1) {
147 DeleteArray(str.start());
148 return format;
149 }
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000150 uint32_t hash = StringHasher::HashSequentialString(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000151 str.start(), len, HEAP->HashSeed());
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000152 return AddOrDisposeString(str.start(), hash);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000153}
154
155
156const char* StringsStorage::GetName(String* name) {
157 if (name->IsString()) {
danno@chromium.orgc612e022011-11-10 11:38:15 +0000158 int length = Min(kMaxNameSize, name->length());
159 SmartArrayPointer<char> data =
160 name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL, 0, length);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000161 uint32_t hash = StringHasher::HashSequentialString(
162 *data, length, name->GetHeap()->HashSeed());
danno@chromium.orgc612e022011-11-10 11:38:15 +0000163 return AddOrDisposeString(data.Detach(), hash);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000164 }
165 return "";
166}
167
168
vegorov@chromium.org42841962010-10-18 11:18:59 +0000169const char* StringsStorage::GetName(int index) {
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000170 return GetFormatted("%d", index);
vegorov@chromium.org42841962010-10-18 11:18:59 +0000171}
172
173
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000174size_t StringsStorage::GetUsedMemorySize() const {
175 size_t size = sizeof(*this);
176 size += sizeof(HashMap::Entry) * names_.capacity();
177 for (HashMap::Entry* p = names_.Start(); p != NULL; p = names_.Next(p)) {
178 size += strlen(reinterpret_cast<const char*>(p->value)) + 1;
179 }
180 return size;
181}
182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000183const char* const CodeEntry::kEmptyNamePrefix = "";
lrn@chromium.org25156de2010-04-06 13:10:27 +0000184
185
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000186void CodeEntry::CopyData(const CodeEntry& source) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000187 tag_ = source.tag_;
188 name_prefix_ = source.name_prefix_;
189 name_ = source.name_;
190 resource_name_ = source.resource_name_;
191 line_number_ = source.line_number_;
192}
193
194
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000195uint32_t CodeEntry::GetCallUid() const {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000196 uint32_t hash = ComputeIntegerHash(tag_, v8::internal::kZeroHashSeed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000197 if (shared_id_ != 0) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000198 hash ^= ComputeIntegerHash(static_cast<uint32_t>(shared_id_),
199 v8::internal::kZeroHashSeed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000200 } else {
201 hash ^= ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000202 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)),
203 v8::internal::kZeroHashSeed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000204 hash ^= ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000205 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)),
206 v8::internal::kZeroHashSeed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000207 hash ^= ComputeIntegerHash(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000208 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)),
209 v8::internal::kZeroHashSeed);
210 hash ^= ComputeIntegerHash(line_number_, v8::internal::kZeroHashSeed);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000211 }
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000212 return hash;
213}
214
215
216bool CodeEntry::IsSameAs(CodeEntry* entry) const {
217 return this == entry
218 || (tag_ == entry->tag_
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000219 && shared_id_ == entry->shared_id_
220 && (shared_id_ != 0
221 || (name_prefix_ == entry->name_prefix_
222 && name_ == entry->name_
223 && resource_name_ == entry->resource_name_
224 && line_number_ == entry->line_number_)));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000225}
226
227
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000228ProfileNode* ProfileNode::FindChild(CodeEntry* entry) {
229 HashMap::Entry* map_entry =
230 children_.Lookup(entry, CodeEntryHash(entry), false);
231 return map_entry != NULL ?
232 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL;
233}
234
235
236ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) {
237 HashMap::Entry* map_entry =
238 children_.Lookup(entry, CodeEntryHash(entry), true);
239 if (map_entry->value == NULL) {
240 // New node added.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000241 ProfileNode* new_node = new ProfileNode(tree_, entry);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000242 map_entry->value = new_node;
243 children_list_.Add(new_node);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000244 }
245 return reinterpret_cast<ProfileNode*>(map_entry->value);
246}
247
248
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000249double ProfileNode::GetSelfMillis() const {
250 return tree_->TicksToMillis(self_ticks_);
251}
252
253
254double ProfileNode::GetTotalMillis() const {
255 return tree_->TicksToMillis(total_ticks_);
256}
257
258
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000259void ProfileNode::Print(int indent) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000260 OS::Print("%5u %5u %*c %s%s [%d]",
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000261 total_ticks_, self_ticks_,
262 indent, ' ',
ager@chromium.org357bf652010-04-12 11:30:10 +0000263 entry_->name_prefix(),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000264 entry_->name(),
265 entry_->security_token_id());
ager@chromium.org357bf652010-04-12 11:30:10 +0000266 if (entry_->resource_name()[0] != '\0')
267 OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number());
268 OS::Print("\n");
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000269 for (HashMap::Entry* p = children_.Start();
270 p != NULL;
271 p = children_.Next(p)) {
272 reinterpret_cast<ProfileNode*>(p->value)->Print(indent + 2);
273 }
274}
275
276
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000277class DeleteNodesCallback {
278 public:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000279 void BeforeTraversingChild(ProfileNode*, ProfileNode*) { }
280
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000281 void AfterAllChildrenTraversed(ProfileNode* node) {
282 delete node;
283 }
284
285 void AfterChildTraversed(ProfileNode*, ProfileNode*) { }
286};
287
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000288
ager@chromium.org357bf652010-04-12 11:30:10 +0000289ProfileTree::ProfileTree()
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000290 : root_entry_(Logger::FUNCTION_TAG,
291 "",
292 "(root)",
293 "",
294 0,
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000295 TokenEnumerator::kNoSecurityToken),
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000296 root_(new ProfileNode(this, &root_entry_)) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000297}
298
299
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000300ProfileTree::~ProfileTree() {
301 DeleteNodesCallback cb;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000302 TraverseDepthFirst(&cb);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000303}
304
305
306void ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) {
307 ProfileNode* node = root_;
308 for (CodeEntry** entry = path.start() + path.length() - 1;
309 entry != path.start() - 1;
310 --entry) {
311 if (*entry != NULL) {
312 node = node->FindOrAddChild(*entry);
313 }
314 }
315 node->IncrementSelfTicks();
316}
317
318
319void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) {
320 ProfileNode* node = root_;
321 for (CodeEntry** entry = path.start();
322 entry != path.start() + path.length();
323 ++entry) {
324 if (*entry != NULL) {
325 node = node->FindOrAddChild(*entry);
326 }
327 }
328 node->IncrementSelfTicks();
329}
330
331
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000332struct NodesPair {
333 NodesPair(ProfileNode* src, ProfileNode* dst)
334 : src(src), dst(dst) { }
335 ProfileNode* src;
336 ProfileNode* dst;
337};
338
339
340class FilteredCloneCallback {
341 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000342 FilteredCloneCallback(ProfileNode* dst_root, int security_token_id)
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000343 : stack_(10),
344 security_token_id_(security_token_id) {
345 stack_.Add(NodesPair(NULL, dst_root));
346 }
347
348 void BeforeTraversingChild(ProfileNode* parent, ProfileNode* child) {
349 if (IsTokenAcceptable(child->entry()->security_token_id(),
350 parent->entry()->security_token_id())) {
351 ProfileNode* clone = stack_.last().dst->FindOrAddChild(child->entry());
352 clone->IncreaseSelfTicks(child->self_ticks());
353 stack_.Add(NodesPair(child, clone));
354 } else {
355 // Attribute ticks to parent node.
356 stack_.last().dst->IncreaseSelfTicks(child->self_ticks());
357 }
358 }
359
360 void AfterAllChildrenTraversed(ProfileNode* parent) { }
361
362 void AfterChildTraversed(ProfileNode*, ProfileNode* child) {
363 if (stack_.last().src == child) {
364 stack_.RemoveLast();
365 }
366 }
367
368 private:
369 bool IsTokenAcceptable(int token, int parent_token) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000370 if (token == TokenEnumerator::kNoSecurityToken
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000371 || token == security_token_id_) return true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000372 if (token == TokenEnumerator::kInheritsSecurityToken) {
373 ASSERT(parent_token != TokenEnumerator::kInheritsSecurityToken);
374 return parent_token == TokenEnumerator::kNoSecurityToken
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000375 || parent_token == security_token_id_;
376 }
377 return false;
378 }
379
380 List<NodesPair> stack_;
381 int security_token_id_;
382};
383
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000384void ProfileTree::FilteredClone(ProfileTree* src, int security_token_id) {
385 ms_to_ticks_scale_ = src->ms_to_ticks_scale_;
386 FilteredCloneCallback cb(root_, security_token_id);
387 src->TraverseDepthFirst(&cb);
388 CalculateTotalTicks();
389}
390
391
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000392void ProfileTree::SetTickRatePerMs(double ticks_per_ms) {
393 ms_to_ticks_scale_ = ticks_per_ms > 0 ? 1.0 / ticks_per_ms : 1.0;
394}
395
396
lrn@chromium.org25156de2010-04-06 13:10:27 +0000397class Position {
398 public:
399 explicit Position(ProfileNode* node)
400 : node(node), child_idx_(0) { }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000401 INLINE(ProfileNode* current_child()) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000402 return node->children()->at(child_idx_);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000403 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000404 INLINE(bool has_current_child()) {
405 return child_idx_ < node->children()->length();
406 }
407 INLINE(void next_child()) { ++child_idx_; }
408
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000409 ProfileNode* node;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000410 private:
411 int child_idx_;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000412};
413
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000414
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000415// Non-recursive implementation of a depth-first post-order tree traversal.
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000416template <typename Callback>
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000417void ProfileTree::TraverseDepthFirst(Callback* callback) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000418 List<Position> stack(10);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000419 stack.Add(Position(root_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000420 while (stack.length() > 0) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000421 Position& current = stack.last();
lrn@chromium.org25156de2010-04-06 13:10:27 +0000422 if (current.has_current_child()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000423 callback->BeforeTraversingChild(current.node, current.current_child());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000424 stack.Add(Position(current.current_child()));
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000425 } else {
426 callback->AfterAllChildrenTraversed(current.node);
427 if (stack.length() > 1) {
428 Position& parent = stack[stack.length() - 2];
429 callback->AfterChildTraversed(parent.node, current.node);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000430 parent.next_child();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000431 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000432 // Remove child from the stack.
433 stack.RemoveLast();
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000434 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000435 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000436}
437
438
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000439class CalculateTotalTicksCallback {
440 public:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000441 void BeforeTraversingChild(ProfileNode*, ProfileNode*) { }
442
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000443 void AfterAllChildrenTraversed(ProfileNode* node) {
444 node->IncreaseTotalTicks(node->self_ticks());
445 }
446
447 void AfterChildTraversed(ProfileNode* parent, ProfileNode* child) {
448 parent->IncreaseTotalTicks(child->total_ticks());
449 }
450};
451
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000452
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000453void ProfileTree::CalculateTotalTicks() {
454 CalculateTotalTicksCallback cb;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000455 TraverseDepthFirst(&cb);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000456}
457
458
459void ProfileTree::ShortPrint() {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000460 OS::Print("root: %u %u %.2fms %.2fms\n",
461 root_->total_ticks(), root_->self_ticks(),
462 root_->GetTotalMillis(), root_->GetSelfMillis());
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000463}
464
465
466void CpuProfile::AddPath(const Vector<CodeEntry*>& path) {
467 top_down_.AddPathFromEnd(path);
468 bottom_up_.AddPathFromStart(path);
469}
470
471
472void CpuProfile::CalculateTotalTicks() {
473 top_down_.CalculateTotalTicks();
474 bottom_up_.CalculateTotalTicks();
475}
476
477
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000478void CpuProfile::SetActualSamplingRate(double actual_sampling_rate) {
479 top_down_.SetTickRatePerMs(actual_sampling_rate);
480 bottom_up_.SetTickRatePerMs(actual_sampling_rate);
481}
482
483
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000484CpuProfile* CpuProfile::FilteredClone(int security_token_id) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000485 ASSERT(security_token_id != TokenEnumerator::kNoSecurityToken);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000486 CpuProfile* clone = new CpuProfile(title_, uid_);
487 clone->top_down_.FilteredClone(&top_down_, security_token_id);
488 clone->bottom_up_.FilteredClone(&bottom_up_, security_token_id);
489 return clone;
490}
491
492
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000493void CpuProfile::ShortPrint() {
494 OS::Print("top down ");
495 top_down_.ShortPrint();
496 OS::Print("bottom up ");
497 bottom_up_.ShortPrint();
498}
499
500
501void CpuProfile::Print() {
502 OS::Print("[Top down]:\n");
503 top_down_.Print();
504 OS::Print("[Bottom up]:\n");
505 bottom_up_.Print();
506}
507
508
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000509CodeEntry* const CodeMap::kSharedFunctionCodeEntry = NULL;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000510const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL;
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000511
512
lrn@chromium.org34e60782011-09-15 07:25:40 +0000513void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) {
514 DeleteAllCoveredCode(addr, addr + size);
515 CodeTree::Locator locator;
516 tree_.Insert(addr, &locator);
517 locator.set_value(CodeEntryInfo(entry, size));
518}
519
520
521void CodeMap::DeleteAllCoveredCode(Address start, Address end) {
522 List<Address> to_delete;
523 Address addr = end - 1;
524 while (addr >= start) {
525 CodeTree::Locator locator;
526 if (!tree_.FindGreatestLessThan(addr, &locator)) break;
527 Address start2 = locator.key(), end2 = start2 + locator.value().size;
528 if (start2 < end && start < end2) to_delete.Add(start2);
529 addr = start2 - 1;
530 }
531 for (int i = 0; i < to_delete.length(); ++i) tree_.Remove(to_delete[i]);
532}
533
534
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000535CodeEntry* CodeMap::FindEntry(Address addr) {
536 CodeTree::Locator locator;
537 if (tree_.FindGreatestLessThan(addr, &locator)) {
538 // locator.key() <= addr. Need to check that addr is within entry.
539 const CodeEntryInfo& entry = locator.value();
540 if (addr < (locator.key() + entry.size))
541 return entry.entry;
542 }
543 return NULL;
544}
545
546
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000547int CodeMap::GetSharedId(Address addr) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000548 CodeTree::Locator locator;
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000549 // For shared function entries, 'size' field is used to store their IDs.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000550 if (tree_.Find(addr, &locator)) {
551 const CodeEntryInfo& entry = locator.value();
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000552 ASSERT(entry.entry == kSharedFunctionCodeEntry);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000553 return entry.size;
554 } else {
555 tree_.Insert(addr, &locator);
whesse@chromium.orgb08986c2011-03-14 16:13:42 +0000556 int id = next_shared_id_++;
557 locator.set_value(CodeEntryInfo(kSharedFunctionCodeEntry, id));
558 return id;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000559 }
560}
561
562
lrn@chromium.org34e60782011-09-15 07:25:40 +0000563void CodeMap::MoveCode(Address from, Address to) {
564 if (from == to) return;
565 CodeTree::Locator locator;
566 if (!tree_.Find(from, &locator)) return;
567 CodeEntryInfo entry = locator.value();
568 tree_.Remove(from);
569 AddCode(to, entry.entry, entry.size);
570}
571
572
lrn@chromium.org25156de2010-04-06 13:10:27 +0000573void CodeMap::CodeTreePrinter::Call(
574 const Address& key, const CodeMap::CodeEntryInfo& value) {
575 OS::Print("%p %5d %s\n", key, value.size, value.entry->name());
576}
577
578
579void CodeMap::Print() {
580 CodeTreePrinter printer;
581 tree_.ForEach(&printer);
582}
583
584
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000585CpuProfilesCollection::CpuProfilesCollection()
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000586 : profiles_uids_(UidsMatch),
lrn@chromium.org25156de2010-04-06 13:10:27 +0000587 current_profiles_semaphore_(OS::CreateSemaphore(1)) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000588 // Create list of unabridged profiles.
589 profiles_by_token_.Add(new List<CpuProfile*>());
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000590}
591
592
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000593static void DeleteCodeEntry(CodeEntry** entry_ptr) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000594 delete *entry_ptr;
595}
596
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000597static void DeleteCpuProfile(CpuProfile** profile_ptr) {
598 delete *profile_ptr;
599}
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000600
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000601static void DeleteProfilesList(List<CpuProfile*>** list_ptr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000602 if (*list_ptr != NULL) {
603 (*list_ptr)->Iterate(DeleteCpuProfile);
604 delete *list_ptr;
605 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000606}
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000607
608CpuProfilesCollection::~CpuProfilesCollection() {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000609 delete current_profiles_semaphore_;
610 current_profiles_.Iterate(DeleteCpuProfile);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000611 detached_profiles_.Iterate(DeleteCpuProfile);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000612 profiles_by_token_.Iterate(DeleteProfilesList);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000613 code_entries_.Iterate(DeleteCodeEntry);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000614}
615
616
lrn@chromium.org25156de2010-04-06 13:10:27 +0000617bool CpuProfilesCollection::StartProfiling(const char* title, unsigned uid) {
618 ASSERT(uid > 0);
619 current_profiles_semaphore_->Wait();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000620 if (current_profiles_.length() >= kMaxSimultaneousProfiles) {
621 current_profiles_semaphore_->Signal();
622 return false;
623 }
lrn@chromium.org25156de2010-04-06 13:10:27 +0000624 for (int i = 0; i < current_profiles_.length(); ++i) {
625 if (strcmp(current_profiles_[i]->title(), title) == 0) {
626 // Ignore attempts to start profile with the same title.
627 current_profiles_semaphore_->Signal();
628 return false;
629 }
630 }
631 current_profiles_.Add(new CpuProfile(title, uid));
632 current_profiles_semaphore_->Signal();
633 return true;
634}
635
636
637bool CpuProfilesCollection::StartProfiling(String* title, unsigned uid) {
638 return StartProfiling(GetName(title), uid);
639}
640
641
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000642CpuProfile* CpuProfilesCollection::StopProfiling(int security_token_id,
643 const char* title,
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000644 double actual_sampling_rate) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000645 const int title_len = StrLength(title);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000646 CpuProfile* profile = NULL;
647 current_profiles_semaphore_->Wait();
648 for (int i = current_profiles_.length() - 1; i >= 0; --i) {
649 if (title_len == 0 || strcmp(current_profiles_[i]->title(), title) == 0) {
650 profile = current_profiles_.Remove(i);
651 break;
652 }
653 }
654 current_profiles_semaphore_->Signal();
655
656 if (profile != NULL) {
657 profile->CalculateTotalTicks();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000658 profile->SetActualSamplingRate(actual_sampling_rate);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000659 List<CpuProfile*>* unabridged_list =
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000660 profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000661 unabridged_list->Add(profile);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000662 HashMap::Entry* entry =
663 profiles_uids_.Lookup(reinterpret_cast<void*>(profile->uid()),
664 static_cast<uint32_t>(profile->uid()),
665 true);
666 ASSERT(entry->value == NULL);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000667 entry->value = reinterpret_cast<void*>(unabridged_list->length() - 1);
668 return GetProfile(security_token_id, profile->uid());
lrn@chromium.org25156de2010-04-06 13:10:27 +0000669 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000670 return NULL;
lrn@chromium.org25156de2010-04-06 13:10:27 +0000671}
672
673
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000674CpuProfile* CpuProfilesCollection::GetProfile(int security_token_id,
675 unsigned uid) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000676 int index = GetProfileIndex(uid);
677 if (index < 0) return NULL;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000678 List<CpuProfile*>* unabridged_list =
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000679 profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
680 if (security_token_id == TokenEnumerator::kNoSecurityToken) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000681 return unabridged_list->at(index);
682 }
683 List<CpuProfile*>* list = GetProfilesList(security_token_id);
684 if (list->at(index) == NULL) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000685 (*list)[index] =
686 unabridged_list->at(index)->FilteredClone(security_token_id);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000687 }
688 return list->at(index);
689}
690
691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000692int CpuProfilesCollection::GetProfileIndex(unsigned uid) {
693 HashMap::Entry* entry = profiles_uids_.Lookup(reinterpret_cast<void*>(uid),
694 static_cast<uint32_t>(uid),
695 false);
696 return entry != NULL ?
697 static_cast<int>(reinterpret_cast<intptr_t>(entry->value)) : -1;
698}
699
700
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000701bool CpuProfilesCollection::IsLastProfile(const char* title) {
702 // Called from VM thread, and only it can mutate the list,
703 // so no locking is needed here.
704 if (current_profiles_.length() != 1) return false;
705 return StrLength(title) == 0
706 || strcmp(current_profiles_[0]->title(), title) == 0;
707}
708
709
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000710void CpuProfilesCollection::RemoveProfile(CpuProfile* profile) {
711 // Called from VM thread for a completed profile.
712 unsigned uid = profile->uid();
713 int index = GetProfileIndex(uid);
714 if (index < 0) {
715 detached_profiles_.RemoveElement(profile);
716 return;
717 }
718 profiles_uids_.Remove(reinterpret_cast<void*>(uid),
719 static_cast<uint32_t>(uid));
720 // Decrement all indexes above the deleted one.
721 for (HashMap::Entry* p = profiles_uids_.Start();
722 p != NULL;
723 p = profiles_uids_.Next(p)) {
724 intptr_t p_index = reinterpret_cast<intptr_t>(p->value);
725 if (p_index > index) {
726 p->value = reinterpret_cast<void*>(p_index - 1);
727 }
728 }
729 for (int i = 0; i < profiles_by_token_.length(); ++i) {
730 List<CpuProfile*>* list = profiles_by_token_[i];
731 if (list != NULL && index < list->length()) {
732 // Move all filtered clones into detached_profiles_,
733 // so we can know that they are still in use.
734 CpuProfile* cloned_profile = list->Remove(index);
735 if (cloned_profile != NULL && cloned_profile != profile) {
736 detached_profiles_.Add(cloned_profile);
737 }
738 }
739 }
740}
741
742
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000743int CpuProfilesCollection::TokenToIndex(int security_token_id) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000744 ASSERT(TokenEnumerator::kNoSecurityToken == -1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000745 return security_token_id + 1; // kNoSecurityToken -> 0, 0 -> 1, ...
746}
747
748
749List<CpuProfile*>* CpuProfilesCollection::GetProfilesList(
750 int security_token_id) {
751 const int index = TokenToIndex(security_token_id);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000752 const int lists_to_add = index - profiles_by_token_.length() + 1;
753 if (lists_to_add > 0) profiles_by_token_.AddBlock(NULL, lists_to_add);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000754 List<CpuProfile*>* unabridged_list =
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000755 profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000756 const int current_count = unabridged_list->length();
757 if (profiles_by_token_[index] == NULL) {
758 profiles_by_token_[index] = new List<CpuProfile*>(current_count);
759 }
760 List<CpuProfile*>* list = profiles_by_token_[index];
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000761 const int profiles_to_add = current_count - list->length();
762 if (profiles_to_add > 0) list->AddBlock(NULL, profiles_to_add);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000763 return list;
764}
765
766
767List<CpuProfile*>* CpuProfilesCollection::Profiles(int security_token_id) {
768 List<CpuProfile*>* unabridged_list =
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000769 profiles_by_token_[TokenToIndex(TokenEnumerator::kNoSecurityToken)];
770 if (security_token_id == TokenEnumerator::kNoSecurityToken) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000771 return unabridged_list;
772 }
773 List<CpuProfile*>* list = GetProfilesList(security_token_id);
774 const int current_count = unabridged_list->length();
775 for (int i = 0; i < current_count; ++i) {
776 if (list->at(i) == NULL) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000777 (*list)[i] = unabridged_list->at(i)->FilteredClone(security_token_id);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000778 }
779 }
780 return list;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000781}
782
783
784CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
785 String* name,
786 String* resource_name,
787 int line_number) {
788 CodeEntry* entry = new CodeEntry(tag,
lrn@chromium.org25156de2010-04-06 13:10:27 +0000789 CodeEntry::kEmptyNamePrefix,
ager@chromium.org357bf652010-04-12 11:30:10 +0000790 GetFunctionName(name),
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000791 GetName(resource_name),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000792 line_number,
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000793 TokenEnumerator::kNoSecurityToken);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000794 code_entries_.Add(entry);
795 return entry;
796}
797
798
799CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
800 const char* name) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000801 CodeEntry* entry = new CodeEntry(tag,
802 CodeEntry::kEmptyNamePrefix,
ager@chromium.org357bf652010-04-12 11:30:10 +0000803 GetFunctionName(name),
lrn@chromium.org25156de2010-04-06 13:10:27 +0000804 "",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000805 v8::CpuProfileNode::kNoLineNumberInfo,
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000806 TokenEnumerator::kNoSecurityToken);
lrn@chromium.org25156de2010-04-06 13:10:27 +0000807 code_entries_.Add(entry);
808 return entry;
809}
810
811
812CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
813 const char* name_prefix,
814 String* name) {
815 CodeEntry* entry = new CodeEntry(tag,
816 name_prefix,
817 GetName(name),
818 "",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000819 v8::CpuProfileNode::kNoLineNumberInfo,
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000820 TokenEnumerator::kInheritsSecurityToken);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000821 code_entries_.Add(entry);
822 return entry;
823}
824
825
826CodeEntry* CpuProfilesCollection::NewCodeEntry(Logger::LogEventsAndTags tag,
827 int args_count) {
lrn@chromium.org25156de2010-04-06 13:10:27 +0000828 CodeEntry* entry = new CodeEntry(tag,
829 "args_count: ",
830 GetName(args_count),
831 "",
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000832 v8::CpuProfileNode::kNoLineNumberInfo,
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000833 TokenEnumerator::kInheritsSecurityToken);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000834 code_entries_.Add(entry);
835 return entry;
836}
837
838
lrn@chromium.org25156de2010-04-06 13:10:27 +0000839void CpuProfilesCollection::AddPathToCurrentProfiles(
840 const Vector<CodeEntry*>& path) {
841 // As starting / stopping profiles is rare relatively to this
842 // method, we don't bother minimizing the duration of lock holding,
843 // e.g. copying contents of the list to a local vector.
844 current_profiles_semaphore_->Wait();
845 for (int i = 0; i < current_profiles_.length(); ++i) {
846 current_profiles_[i]->AddPath(path);
847 }
848 current_profiles_semaphore_->Signal();
849}
850
851
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000852void SampleRateCalculator::Tick() {
853 if (--wall_time_query_countdown_ == 0)
854 UpdateMeasurements(OS::TimeCurrentMillis());
855}
856
857
858void SampleRateCalculator::UpdateMeasurements(double current_time) {
859 if (measurements_count_++ != 0) {
860 const double measured_ticks_per_ms =
861 (kWallTimeQueryIntervalMs * ticks_per_ms_) /
862 (current_time - last_wall_time_);
863 // Update the average value.
864 ticks_per_ms_ +=
865 (measured_ticks_per_ms - ticks_per_ms_) / measurements_count_;
866 // Update the externally accessible result.
867 result_ = static_cast<AtomicWord>(ticks_per_ms_ * kResultScale);
868 }
869 last_wall_time_ = current_time;
870 wall_time_query_countdown_ =
871 static_cast<unsigned>(kWallTimeQueryIntervalMs * ticks_per_ms_);
872}
873
874
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000875const char* const ProfileGenerator::kAnonymousFunctionName =
876 "(anonymous function)";
877const char* const ProfileGenerator::kProgramEntryName =
878 "(program)";
879const char* const ProfileGenerator::kGarbageCollectorEntryName =
880 "(garbage collector)";
ager@chromium.org357bf652010-04-12 11:30:10 +0000881
882
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000883ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles)
ager@chromium.org357bf652010-04-12 11:30:10 +0000884 : profiles_(profiles),
885 program_entry_(
886 profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)),
887 gc_entry_(
888 profiles->NewCodeEntry(Logger::BUILTIN_TAG,
889 kGarbageCollectorEntryName)) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000890}
891
892
893void ProfileGenerator::RecordTickSample(const TickSample& sample) {
ager@chromium.org357bf652010-04-12 11:30:10 +0000894 // Allocate space for stack frames + pc + function + vm-state.
895 ScopedVector<CodeEntry*> entries(sample.frames_count + 3);
896 // As actual number of decoded code entries may vary, initialize
897 // entries vector with NULL values.
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000898 CodeEntry** entry = entries.start();
ager@chromium.org357bf652010-04-12 11:30:10 +0000899 memset(entry, 0, entries.length() * sizeof(*entry));
900 if (sample.pc != NULL) {
901 *entry++ = code_map_.FindEntry(sample.pc);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000902
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000903 if (sample.has_external_callback) {
904 // Don't use PC when in external callback code, as it can point
905 // inside callback's code, and we will erroneously report
906 // that a callback calls itself.
907 *(entries.start()) = NULL;
908 *entry++ = code_map_.FindEntry(sample.external_callback);
909 } else if (sample.tos != NULL) {
910 // Find out, if top of stack was pointing inside a JS function
911 // meaning that we have encountered a frameless invocation.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000912 *entry = code_map_.FindEntry(sample.tos);
ager@chromium.org357bf652010-04-12 11:30:10 +0000913 if (*entry != NULL && !(*entry)->is_js_function()) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000914 *entry = NULL;
ager@chromium.org357bf652010-04-12 11:30:10 +0000915 }
916 entry++;
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000917 }
ager@chromium.org357bf652010-04-12 11:30:10 +0000918
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000919 for (const Address* stack_pos = sample.stack,
ager@chromium.org357bf652010-04-12 11:30:10 +0000920 *stack_end = stack_pos + sample.frames_count;
921 stack_pos != stack_end;
922 ++stack_pos) {
923 *entry++ = code_map_.FindEntry(*stack_pos);
924 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000925 }
926
ager@chromium.org357bf652010-04-12 11:30:10 +0000927 if (FLAG_prof_browser_mode) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +0000928 bool no_symbolized_entries = true;
929 for (CodeEntry** e = entries.start(); e != entry; ++e) {
930 if (*e != NULL) {
931 no_symbolized_entries = false;
932 break;
933 }
934 }
935 // If no frames were symbolized, put the VM state entry in.
936 if (no_symbolized_entries) {
937 *entry++ = EntryForVMState(sample.state);
938 }
whesse@chromium.orgcec079d2010-03-22 14:44:04 +0000939 }
940
lrn@chromium.org25156de2010-04-06 13:10:27 +0000941 profiles_->AddPathToCurrentProfiles(entries);
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000942}
943
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000944
fschneider@chromium.org086aac62010-03-17 13:18:24 +0000945} } // namespace v8::internal