Upstream version 11.39.260.0
[platform/framework/web/crosswalk.git] / src / v8 / src / xdk-utils.cc
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #include "src/frames-inl.h"
8 #include "src/xdk-utils.h"
9
10 namespace v8 {
11 namespace internal {
12
13 static bool AddressesMatch(void* key1, void* key2) {
14   return key1 == key2;
15 }
16
17
18 static uint32_t CharAddressHash(char* addr) {
19   return ComputeIntegerHash(static_cast<uint32_t>(
20       reinterpret_cast<uintptr_t>(addr)),
21       v8::internal::kZeroHashSeed);
22 }
23
24
25 static uint32_t AddressHash(Address addr) {
26   return ComputeIntegerHash(static_cast<uint32_t>(
27       reinterpret_cast<uintptr_t>(addr)),
28       v8::internal::kZeroHashSeed);
29 }
30
31
32 ClassNames::ClassNames(StringsStorage* names)
33     : counter_(0),
34     char_to_idx_(AddressesMatch),
35     names_(names) {
36 }
37
38
39 unsigned ClassNames::registerName(const char* name) {
40   // since const char is retained outside and cannot be moved, we rely on this
41   // and just compare the pointers. It should be enough for the strings from the
42   // only one StringStorage
43   unsigned counter;
44   HashMap::Entry* entry = char_to_idx_.Lookup(const_cast<char*>(name),
45       CharAddressHash(const_cast<char*>(name)),
46       true);
47   if (entry->value == NULL) {
48     counter = ++counter_;
49     entry->value = reinterpret_cast<void*>(counter);
50   } else {
51     counter = static_cast<unsigned>(reinterpret_cast<uintptr_t>(entry->value));
52   }
53   return counter;
54 }
55
56
57 std::string ClassNames::SerializeChunk() {
58   std::stringstream serialized;
59   for (HashMap::Entry* p = char_to_idx_.Start(); p != NULL;
60       p = char_to_idx_.Next(p)) {
61     serialized << static_cast<unsigned>(
62         reinterpret_cast<uintptr_t>(p->value)) << "," <<
63         reinterpret_cast<char*>(p->key) << std::endl;
64   }
65
66   return serialized.str();
67 }
68
69
70 String* ClassNames::GetConstructorName(Address address) {
71   HeapObject *heap_object = HeapObject::FromAddress(address);
72   bool is_js_object = heap_object->IsJSObject();
73   if (!is_js_object) {
74     // TODO(amalyshe): look for another function for taking the class name
75     // String* constructor_name = object2->constructor_name();
76     return NULL;
77   }
78   JSObject* object = JSObject::cast(heap_object);
79   Heap* heap = object->GetHeap();
80   if (object->IsJSFunction()) return heap->closure_string();
81   return object->constructor_name();
82 }
83
84
85 // -----------------------------------------------------------------------------
86 ShadowStack::ShadowStack() {
87   last_index_ = 1;
88   serializedCounter_ = last_index_;
89   root_.index_ = 0;
90   root_.parent_ = NULL;
91   root_.callsite_ = 0;
92 }
93
94
95 ShadowStack::~ShadowStack() {
96   // erasing all objects from the current container
97   std::map<unsigned, CallTree*>::iterator eit = allNodes_.begin();
98   while (eit != allNodes_.end()) {
99     delete eit->second;
100     eit++;
101   }
102 }
103
104
105 unsigned ShadowStack::registerStack(const List<unsigned>& shadow_stack_) {
106     // look for the latest node
107     CallTree* pNode = &root_;
108     // go over all entries and add them to the tree if they are not in the map
109     int i, j;
110     for (i = shadow_stack_.length()-1; i != -1; i--) {
111       std::map<unsigned, CallTree*>::iterator it =
112           pNode->children_.find(shadow_stack_[i]);
113       if (it == pNode->children_.end())
114           break;
115       pNode = it->second;
116     }
117     // verification if we need to add something or not
118     for (j = i; j != -1; j--) {
119       CallTree* pNodeTmp = new CallTree;
120       pNodeTmp->index_ = last_index_++;
121       pNodeTmp->parent_ = pNode;
122       pNodeTmp->callsite_ = shadow_stack_[j];
123       pNode->children_[shadow_stack_[j]] = pNodeTmp;
124       allNodes_[pNodeTmp->index_] = pNodeTmp;
125       pNode = pNodeTmp;
126     }
127     return pNode->index_;
128 }
129
130
131 std::string ShadowStack::SerializeChunk() {
132   std::stringstream str;
133   std::map<unsigned, CallTree*>::iterator it =
134       allNodes_.find(serializedCounter_);
135   while (it!= allNodes_.end()) {
136     str << it->first << "," << it->second->callsite_ << "," <<
137         it->second->parent_->index_ << std::endl;
138     it++;
139   }
140
141   serializedCounter_ = last_index_;
142   return str.str();
143 }
144
145
146 // -----------------------------------------------------------------------------
147 static bool SymInfoMatch(void* key1, void* key2) {
148   SymInfoKey* key_c1 = reinterpret_cast<SymInfoKey*>(key1);
149   SymInfoKey* key_c2 = reinterpret_cast<SymInfoKey*>(key2);
150   return *key_c1 == *key_c2;
151 }
152
153
154 static uint32_t SymInfoHash(const SymInfoKey& key) {
155   uint32_t hash = 0;
156   // take the low 16 bits of function_id_
157   hash |= (key.function_id_ & 0xffff);
158   // take the low 8 bits of line_ and column_ and init highest bits
159   hash |= ((key.line_ & 0xff) << 16);
160   hash |= ((key.column_ & 0xff) << 14);
161
162   return hash;
163 }
164
165
166 struct SymbolCached {
167   unsigned int symbol_id_;
168   uintptr_t function_;
169 };
170
171
172 SymbolsStorage::SymbolsStorage(Heap* heap, StringsStorage* names) :
173   symbols_(SymInfoMatch),
174   curSym_(1),
175   sym_info_hash_(AddressesMatch),
176   heap_(heap),
177   names_(names) {
178   reserved_key_ = new SymInfoKey();
179 }
180
181
182 SymbolsStorage::~SymbolsStorage() {
183   // go over map and delete all keys and values
184   for (HashMap::Entry* p = symbols_.Start(); p != NULL; p = symbols_.Next(p)) {
185     delete reinterpret_cast<SymInfoValue*>(p->value);
186     delete reinterpret_cast<SymInfoKey*>(p->key);
187   }
188   delete reserved_key_;
189 }
190
191
192 unsigned SymbolsStorage::registerSymInfo(size_t functionId,
193                                          std::string functionName,
194                                          std::string sourceName,
195                                          unsigned line,
196                                          unsigned column) {
197   if (sourceName.empty()) {
198     sourceName = "unknown";
199   }
200
201   reserved_key_->function_id_ = functionId;
202   reserved_key_->line_ = line;
203   reserved_key_->column_ = column;
204
205   HashMap::Entry* entry = symbols_.Lookup(reserved_key_,
206                                           SymInfoHash(*reserved_key_), true);
207   if (entry->value) {
208     return reinterpret_cast<SymInfoValue*>(entry->value)->symId_;
209   }
210
211   // else initialize by new one
212   SymInfoValue* value = new SymInfoValue;
213   value->symId_ = curSym_++;
214   value->funcName_ = functionName;
215   value->sourceFile_ = sourceName;
216   entry->value = value;
217
218   // compensation for registered one
219   reserved_key_ = new SymInfoKey();
220
221   return value->symId_;
222 }
223
224
225 std::string SymbolsStorage::SerializeChunk() {
226   std::stringstream serialized;
227   for (HashMap::Entry* p = symbols_.Start(); p != NULL; p = symbols_.Next(p)) {
228     SymInfoValue* v = reinterpret_cast<SymInfoValue*>(p->value);
229     SymInfoKey* k = reinterpret_cast<SymInfoKey*>(p->key);
230     serialized << v->symId_ << "," << k->function_id_ << "," <<
231         v->funcName_ << "," << v->sourceFile_ << "," <<
232         k->line_ << "," << k->column_ << std::endl;
233   }
234
235   return serialized.str();
236 }
237
238
239 unsigned SymbolsStorage::FindOrRegisterFrame(JavaScriptFrame* frame) {
240   SharedFunctionInfo *shared = frame->function()->shared();
241   DCHECK(shared);
242   Isolate *isolate = heap_->isolate();
243
244   Address pc = frame->pc();
245   unsigned int symbolId = 0;
246
247   // We don't rely on the address only. Since this is JIT based language,
248   // the address might be occupied by other function
249   // thus we are verifying if the same function takes this place
250   // before we take symbol info from the cache
251   HashMap::Entry* sym_entry = sym_info_hash_.Lookup(
252           reinterpret_cast<void*>(pc), AddressHash(pc), true);
253   if (sym_entry->value == NULL ||
254       (reinterpret_cast<SymbolCached*>(sym_entry->value)->function_ !=
255         reinterpret_cast<uintptr_t>(frame->function()))) {
256     if (sym_entry->value) {
257       delete reinterpret_cast<SymbolCached*>(sym_entry->value);
258     }
259
260     const char *s = names_->GetFunctionName(shared->DebugName());
261     // trying to get the source name and line#
262     Code *code = Code::cast(isolate->FindCodeObject(pc));
263     if (code) {
264       int source_pos = code->SourcePosition(pc);
265       Object *maybe_script = shared->script();
266       if (maybe_script && maybe_script->IsScript()) {
267         Handle<Script> script(Script::cast(maybe_script));
268         if (!script.is_null()) {
269           int line = script->GetLineNumber(source_pos) + 1;
270           // TODO(amalyshe): check if this can be used:
271           // int line = GetScriptLineNumberSafe(script, source_pos) + 1;
272           // TODO(amalyshe): add column number getting
273           int column = 0;  // GetScriptColumnNumber(script, source_pos);
274           Object *script_name_raw = script->name();
275           if (script_name_raw->IsString()) {
276             String *script_name = String::cast(script->name());
277             SmartArrayPointer<char> c_script_name =
278               script_name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
279             symbolId = registerSymInfo((size_t)frame->function(), s,
280                                        c_script_name.get(), line, column);
281           }
282         }
283       }
284     }
285     if (symbolId == 0) {
286       symbolId = registerSymInfo((size_t)frame->function(), s, "", 0, 0);
287     }
288
289     SymbolCached* symCached = new SymbolCached;
290     symCached->function_ = reinterpret_cast<uintptr_t>(frame->function());
291     symCached->symbol_id_ = symbolId;
292     sym_entry->value = symCached;
293   } else {
294     symbolId = reinterpret_cast<SymbolCached*>(sym_entry->value)->symbol_id_;
295   }
296   return symbolId;
297 }
298
299
300 // -----------------------------------------------------------------------------
301 RuntimeInfo::RuntimeInfo(AggregatedChunks* aggregated_chunks):
302   working_set_hash_(AddressesMatch),
303   aggregated_chunks_(aggregated_chunks),
304   AllocatedBeforeCollectionFrame_(0) {
305 }
306
307
308 PostCollectedInfo* RuntimeInfo::FindPostCollectedInfo(Address addr) {
309   HashMap::Entry* entry = working_set_hash_.Lookup(
310           reinterpret_cast<void*>(addr), AddressHash(addr), false);
311   if (entry && entry->value) {
312     PostCollectedInfo* info =
313         reinterpret_cast<PostCollectedInfo*>(entry->value);
314     return info;
315   }
316   return NULL;
317 }
318
319
320 PostCollectedInfo* RuntimeInfo::AddPostCollectedInfo(Address addr,
321                                                     unsigned time_delta,
322                                                     PostCollectedInfo* info) {
323   PostCollectedInfo* info_new = NULL;
324   if (!info) {
325     info_new = new PostCollectedInfo;
326   } else {
327     info_new = info;
328   }
329
330   HashMap::Entry* entry = working_set_hash_.Lookup(
331           reinterpret_cast<void*>(addr), AddressHash(addr), true);
332   DCHECK(entry);
333   if (entry->value != NULL) {
334     // compensation of the wrong deallocation place
335     // we were not able to work the GC epilogue callback because GC is not
336     // iteratable in the prologue
337     // thus we need to mark the object as freed
338     PostCollectedInfo* info_old =
339         static_cast<PostCollectedInfo*>(entry->value);
340     aggregated_chunks_->addObjectToAggregated(info_old, time_delta);
341     delete info_old;
342   }
343
344   entry->value = info_new;
345   return info_new;
346 }
347
348
349 PostCollectedInfo* RuntimeInfo::AddPreCollectionInfo(Address addr,
350                                                      unsigned size) {
351   PostCollectedInfo* info = AddPostCollectedInfo(addr);
352   info->size_ = size;
353   info->timeStamp_ = 0;
354   info->stackId_ = AllocatedBeforeCollectionFrame_;
355   info->className_ = (unsigned)-1;
356   return info;
357 }
358
359
360 void RuntimeInfo::RemoveInfo(Address addr) {
361   working_set_hash_.Remove(reinterpret_cast<void*>(addr), AddressHash(addr));
362 }
363
364
365 void RuntimeInfo::InitABCFrame(unsigned abc_frame) {
366   AllocatedBeforeCollectionFrame_ = abc_frame;
367 }
368
369
370 void RuntimeInfo::CollectGarbaged(unsigned ts) {
371   // iteration over the working_set_hash_
372   for (HashMap::Entry* p = working_set_hash_.Start(); p != NULL;
373       p = working_set_hash_.Next(p)) {
374     if (p->value) {
375       PostCollectedInfo* info = static_cast<PostCollectedInfo*>(p->value);
376       if (info->dirty_ == false) {
377         // need to care of allocated during collection.
378         // if timeStamp_ == 0 this object was allocated before collection
379         // and we don't care of it
380         aggregated_chunks_->addObjectToAggregated(info, ts);
381         delete info;
382         p->value = NULL;
383       } else {
384         info->dirty_ = false;
385       }
386     }
387   }
388 }
389
390
391 //------------------------------------------------------------------------------
392 static bool AggregatedMatch(void* key1, void* key2) {
393   // cast to the AggregatedKey
394   AggregatedKey* key_c1 = reinterpret_cast<AggregatedKey*>(key1);
395   AggregatedKey* key_c2 = reinterpret_cast<AggregatedKey*>(key2);
396   return *key_c1 == *key_c2;
397 }
398
399
400 static uint32_t AggregatedHash(const AggregatedKey& key) {
401   uint32_t hash = 0;
402   // take the low 8 bits of stackId_
403   hash |= (key.stackId_ & 0xff);
404   // take the low 8 bits of classId_ and init hash from 8th to 15th bits
405   hash |= ((key.classId_ & 0xff) << 8);
406   // since times are well graduated it's no sense take the lowest 8 bit
407   // instead this we will move to 3 bits and only then take 8 bits
408   hash |= (((key.tsBegin_ >> 3) & 0xff) << 16);
409   hash |= (((key.tsBegin_ >> 3) & 0xff) << 24);
410   return hash;
411 }
412
413
414 AggregatedChunks::AggregatedChunks() :
415   aggregated_map_(AggregatedMatch),
416   bucketSize_(500) {
417   reserved_key_ = new AggregatedKey();
418 }
419
420
421 AggregatedChunks::~AggregatedChunks() {
422   delete reserved_key_;
423 }
424
425
426 void AggregatedChunks::addObjectToAggregated(PostCollectedInfo* info,
427                                                         unsigned td) {
428   reserved_key_->stackId_ = info->stackId_;
429   reserved_key_->classId_ = info->className_;
430   // get the bucket for the first time
431   reserved_key_->tsBegin_ = info->timeStamp_ - (info->timeStamp_ % bucketSize_);
432   reserved_key_->tsEnd_ = td - (td % bucketSize_);
433
434   HashMap::Entry* aggregated_entry = aggregated_map_.Lookup(reserved_key_,
435                                                 AggregatedHash(*reserved_key_),
436                                                 true);
437   if (aggregated_entry->value) {
438     // no need to store the latest record in the aggregated_keys_list_
439     AggregatedValue* value =
440                 reinterpret_cast<AggregatedValue*>(aggregated_entry->value);
441     value->objects_++;
442     value->size_ += info->size_;
443   } else {
444     reserved_key_ = new AggregatedKey;
445     AggregatedValue* value = new AggregatedValue;
446     value->objects_ = 1;
447     value->size_ = info->size_;
448     aggregated_entry->value = value;
449   }
450 }
451
452
453 std::string AggregatedChunks::SerializeChunk() {
454   std::stringstream schunks;
455   for (HashMap::Entry* p = aggregated_map_.Start(); p != NULL;
456       p = aggregated_map_.Next(p)) {
457     if (p->key && p->value) {
458       AggregatedKey* key = reinterpret_cast<AggregatedKey*>(p->key);
459       AggregatedValue* value = reinterpret_cast<AggregatedValue*>(p->value);
460       schunks <<
461         key->tsBegin_ << "," << key->tsEnd_ << "," <<
462         key->stackId_ << "," << key->classId_ << "," <<
463         value->size_ << "," << value->objects_ << std::endl;
464       delete key;
465       delete value;
466     }
467   }
468
469   aggregated_map_.Clear();
470
471   return schunks.str();
472 }
473
474
475 // -----------------------------------------------------------------------------
476 void References::addReference(const RefId& parent, const RefSet& refSet,
477                                int parentTime) {
478   // looking for the parent in the refMap_
479   PARENTREFMAP::iterator cit = refMap_.find(parent);
480   if (cit != refMap_.end()) {
481     REFERENCESETS& sets = cit->second;
482     REFERENCESETS::iterator it = sets.find(refSet);
483     if (it != sets.end()) {
484       // look for the time
485       TIMETOCOUNT::iterator cittc = it->second.find(parentTime);
486       if (cittc != it->second.end()) {
487         cittc->second++;
488       } else {
489         it->second[parentTime] = 1;
490       }
491     } else {
492       TIMETOCOUNT tc;
493       tc[parentTime] = 1;
494       sets[refSet] = tc;
495     }
496   } else {
497     // adding new parent, new sets
498     REFERENCESETS sets;
499     TIMETOCOUNT tc;
500     tc[parentTime] = 1;
501     sets[refSet] = tc;
502     refMap_[parent] = sets;
503   }
504 }
505
506
507 void References::clear() {
508   refMap_.clear();
509 }
510
511
512 std::string References::serialize() const {
513   std::stringstream str;
514   PARENTREFMAP::const_iterator citrefs = refMap_.begin();
515   while (citrefs != refMap_.end()) {
516     REFERENCESETS::const_iterator citsets = citrefs->second.begin();
517     while (citsets != citrefs->second.end()) {
518       str << citrefs->first.stackId_ << "," << citrefs->first.classId_;
519       // output of length, and content of TIMETOCOUNT
520       str << "," << citsets->second.size();
521       TIMETOCOUNT::const_iterator cittc = citsets->second.begin();
522       while (cittc != citsets->second.end()) {
523         str << "," << cittc->first << "," << cittc->second;
524         cittc++;
525       }
526       REFERENCESET::const_iterator citset = citsets->first.references_.begin();
527       while (citset != citsets->first.references_.end()) {
528         str << "," << citset->stackId_ << "," << citset->classId_<< "," <<
529           citset->field_;
530         citset++;
531       }
532       str << std::endl;
533       citsets++;
534     }
535     citrefs++;
536   }
537   return str.str();
538 }
539
540
541 } }  // namespace v8::internal