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