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