• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2   This file is provided under a dual BSD/GPLv2 license.  When using or
3   redistributing this file, you may do so under either license.
4 
5   GPL LICENSE SUMMARY
6 
7   Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
8 
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of version 2 of the GNU General Public License as
11   published by the Free Software Foundation.
12 
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17 
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21   The full GNU General Public License is included in this distribution
22   in the file called LICENSE.GPL.
23 
24   Contact Information:
25   http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/
26 
27   BSD LICENSE
28 
29   Copyright(c) 2005-2012 Intel Corporation. All rights reserved.
30   All rights reserved.
31 
32   Redistribution and use in source and binary forms, with or without
33   modification, are permitted provided that the following conditions
34   are met:
35 
36     * Redistributions of source code must retain the above copyright
37       notice, this list of conditions and the following disclaimer.
38     * Redistributions in binary form must reproduce the above copyright
39       notice, this list of conditions and the following disclaimer in
40       the documentation and/or other materials provided with the
41       distribution.
42     * Neither the name of Intel Corporation nor the names of its
43       contributors may be used to endorse or promote products derived
44       from this software without specific prior written permission.
45 
46   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
47   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
48   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
49   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
50   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
51   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
52   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
53   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
54   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
55   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
56   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 */
58 
59 #include <stdlib.h>
60 #include <string.h>
61 
62 #include <list>
63 #include <memory>
64 #include <string>
65 #include <unordered_map>
66 #include <vector>
67 
68 #include "v8-vtune.h"
69 #include "vtune-jit.h"
70 
71 namespace vTune {
72 namespace internal {
73 
74 
75 // This class is used to record the JITted code position info for JIT
76 // code profiling.
77 class JITCodeLineInfo {
78  public:
JITCodeLineInfo()79   JITCodeLineInfo() { }
80 
SetPosition(intptr_t pc,int pos)81   void SetPosition(intptr_t pc, int pos) {
82     AddCodeLineInfo(LineNumInfo(pc, pos));
83   }
84 
85   struct LineNumInfo {
LineNumInfovTune::internal::JITCodeLineInfo::LineNumInfo86     LineNumInfo(intptr_t pc, int pos)
87         : pc_(pc), pos_(pos) { }
88 
89     intptr_t pc_;
90     int pos_;
91   };
92 
GetLineNumInfo()93   std::list<LineNumInfo>* GetLineNumInfo() {
94     return &line_num_info_;
95   }
96 
97  private:
AddCodeLineInfo(const LineNumInfo & line_info)98   void AddCodeLineInfo(const LineNumInfo& line_info) {
99 	  line_num_info_.push_back(line_info);
100   }
101   std::list<LineNumInfo> line_num_info_;
102 };
103 
104 struct SameCodeObjects {
operator ()vTune::internal::SameCodeObjects105   bool operator () (void* key1, void* key2) const {
106     return key1 == key2;
107   }
108 };
109 
110 struct HashForCodeObject {
operator ()vTune::internal::HashForCodeObject111   uint32_t operator () (void* code) const {
112     static const uintptr_t kGoldenRatio = 2654435761u;
113     uintptr_t hash = reinterpret_cast<uintptr_t>(code);
114     return static_cast<uint32_t>(hash * kGoldenRatio);
115   }
116 };
117 
118 typedef std::unordered_map<void*, void*, HashForCodeObject, SameCodeObjects>
119     JitInfoMap;
120 
GetEntries()121 static JitInfoMap* GetEntries() {
122   static JitInfoMap* entries;
123   if (entries == NULL) {
124     entries = new JitInfoMap();
125   }
126   return entries;
127 }
128 
IsLineInfoTagged(void * ptr)129 static bool IsLineInfoTagged(void* ptr) {
130   return 0 != (reinterpret_cast<intptr_t>(ptr));
131 }
132 
UntagLineInfo(void * ptr)133 static JITCodeLineInfo* UntagLineInfo(void* ptr) {
134   return reinterpret_cast<JITCodeLineInfo*>(
135     reinterpret_cast<intptr_t>(ptr));
136 }
137 
138 // The parameter str is a mixed pattern which contains the
139 // function name and some other info. It comes from all the
140 // Logger::CodeCreateEvent(...) function. This function get the
141 // pure function name from the input parameter.
GetFunctionNameFromMixedName(const char * str,int length)142 static std::string GetFunctionNameFromMixedName(const char* str, int length) {
143   int index = 0;
144   int count = 0;
145   char* start_ptr = NULL;
146 
147   while (str[index++] != ':' && (index < length)) {}
148 
149   if (str[index] == '*' || str[index] == '~' ) index++;
150   if (index >= length) return std::string();
151 
152   start_ptr = const_cast<char*>(str + index);
153 
154   // Detecting JS and WASM function names. In JitCodeEvent->name.str
155   // JS functions name ends with a space symbol. WASM function name
156   // ends with the latest closing parenthesis.
157   char last_char = ' ';
158   int parenthesis_count = 0;
159   while (index < length) {
160     if (str[index] == '(') {
161       last_char = ')';
162       parenthesis_count++;
163     }
164     if (str[index] == ')') parenthesis_count--;
165     if (str[index] == last_char && parenthesis_count == 0) {
166       if (last_char == ')') count++;
167       break;
168     }
169     count++;
170     index++;
171   }
172 
173   return std::string(start_ptr, count);
174 }
175 
176 // The JitCodeEventHandler for Vtune.
event_handler(const v8::JitCodeEvent * event)177 void VTUNEJITInterface::event_handler(const v8::JitCodeEvent* event) {
178   if (VTUNERUNNING && event != NULL) {
179     switch (event->type) {
180       case v8::JitCodeEvent::CODE_ADDED: {
181         std::unique_ptr<char[]> temp_file_name;
182         std::string temp_method_name = GetFunctionNameFromMixedName(
183             event->name.str, static_cast<int>(event->name.len));
184         std::vector<LineNumberInfo> jmethod_line_number_table;
185         iJIT_Method_Load jmethod;
186         memset(&jmethod, 0, sizeof jmethod);
187         jmethod.method_id = iJIT_GetNewMethodID();
188         jmethod.method_load_address = event->code_start;
189         jmethod.method_size = static_cast<unsigned int>(event->code_len);
190         jmethod.method_name = const_cast<char*>(temp_method_name.c_str());
191 
192         Local<UnboundScript> script = event->script;
193 
194         if (*script != NULL) {
195           // Get the source file name and set it to jmethod.source_file_name
196           if ((*script->GetScriptName())->IsString()) {
197             Local<String> script_name =
198                 Local<String>::Cast(script->GetScriptName());
199             temp_file_name.reset(
200                 new char[script_name->Utf8Length(event->isolate) + 1]);
201             script_name->WriteUtf8(event->isolate, temp_file_name.get());
202             jmethod.source_file_name = temp_file_name.get();
203           }
204 
205           JitInfoMap::iterator entry =
206               GetEntries()->find(event->code_start);
207           if (entry != GetEntries()->end() && IsLineInfoTagged(entry->first)) {
208             JITCodeLineInfo* line_info = UntagLineInfo(entry->second);
209             // Get the line_num_info and set it to jmethod.line_number_table
210             std::list<JITCodeLineInfo::LineNumInfo>* vtunelineinfo =
211                 line_info->GetLineNumInfo();
212 
213             jmethod.line_number_size = (unsigned int)vtunelineinfo->size();
214             jmethod_line_number_table.resize(jmethod.line_number_size);
215             jmethod.line_number_table = jmethod_line_number_table.data();
216 
217             std::list<JITCodeLineInfo::LineNumInfo>::iterator Iter;
218             int index = 0;
219             for (Iter = vtunelineinfo->begin();
220                  Iter != vtunelineinfo->end();
221                  Iter++) {
222               jmethod.line_number_table[index].Offset =
223                   static_cast<unsigned int>(Iter->pc_);
224               jmethod.line_number_table[index++].LineNumber =
225                   script->GetLineNumber(Iter->pos_) + 1;
226             }
227             GetEntries()->erase(event->code_start);
228           }
229         } else if (event->wasm_source_info != nullptr) {
230           const char* filename = event->wasm_source_info->filename;
231           size_t filename_size = event->wasm_source_info->filename_size;
232           const v8::JitCodeEvent::line_info_t* line_number_table =
233               event->wasm_source_info->line_number_table;
234           size_t line_number_table_size =
235               event->wasm_source_info->line_number_table_size;
236 
237           temp_file_name.reset(new char[filename_size + 1]);
238           memcpy(temp_file_name.get(), filename, filename_size);
239           temp_file_name[filename_size] = '\0';
240           jmethod.source_file_name = temp_file_name.get();
241 
242           jmethod.line_number_size = line_number_table_size;
243           jmethod_line_number_table.resize(jmethod.line_number_size);
244           jmethod.line_number_table = jmethod_line_number_table.data();
245 
246           for (size_t index = 0; index < line_number_table_size; ++index) {
247             jmethod.line_number_table[index].LineNumber =
248                 line_number_table[index].pos;
249             jmethod.line_number_table[index].Offset =
250                 line_number_table[index].offset;
251           }
252         }
253 
254         iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
255                          reinterpret_cast<void*>(&jmethod));
256         break;
257       }
258       // TODO(chunyang.dai@intel.com): code_move will be supported.
259       case v8::JitCodeEvent::CODE_MOVED:
260         break;
261       // Currently the CODE_REMOVED event is not issued.
262       case v8::JitCodeEvent::CODE_REMOVED:
263         break;
264       case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
265         JITCodeLineInfo* line_info =
266             reinterpret_cast<JITCodeLineInfo*>(event->user_data);
267         if (line_info != NULL) {
268           line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset),
269                                  static_cast<int>(event->line_info.pos));
270         }
271         break;
272       }
273       case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
274         v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
275         temp_event->user_data = new JITCodeLineInfo();
276         break;
277       }
278       case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
279         GetEntries()->insert(std::pair <void*, void*>(event->code_start, event->user_data));
280         break;
281       }
282       default:
283         break;
284     }
285   }
286   return;
287 }
288 
289 }  // namespace internal
290 
GetVtuneCodeEventHandler()291 v8::JitCodeEventHandler GetVtuneCodeEventHandler() {
292   v8::V8::SetFlagsFromString("--no-compact-code-space");
293   return vTune::internal::VTUNEJITInterface::event_handler;
294 }
295 
296 }  // namespace vTune
297