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#include <string.h>
59
60#ifdef WIN32
61#include <hash_map>
62using namespace std;
63#else
64// To avoid GCC 4.4 compilation warning about hash_map being deprecated.
65#define OLD_DEPRECATED __DEPRECATED
66#undef __DEPRECATED
67#if defined (ANDROID)
68#include <hash_map>
69using namespace std;
70#else
71#include <ext/hash_map>
72using namespace __gnu_cxx;
73#endif
74#define __DEPRECATED OLD_DEPRECATED
75#endif
76
77#include <list>
78
79#include "v8-vtune.h"
80#include "vtune-jit.h"
81
82namespace vTune {
83namespace internal {
84
85
86// This class is used to record the JITted code position info for JIT
87// code profiling.
88class JITCodeLineInfo {
89 public:
90  JITCodeLineInfo() { }
91
92  void SetPosition(intptr_t pc, int pos) {
93    AddCodeLineInfo(LineNumInfo(pc, pos));
94  }
95
96  struct LineNumInfo {
97    LineNumInfo(intptr_t pc, int pos)
98        : pc_(pc), pos_(pos) { }
99
100    intptr_t pc_;
101    int pos_;
102  };
103
104  std::list<LineNumInfo>* GetLineNumInfo() {
105    return &line_num_info_;
106  }
107
108 private:
109  void AddCodeLineInfo(const LineNumInfo& line_info) {
110	  line_num_info_.push_back(line_info);
111  }
112  std::list<LineNumInfo> line_num_info_;
113};
114
115struct SameCodeObjects {
116  bool operator () (void* key1, void* key2) const {
117    return key1 == key2;
118  }
119};
120
121struct HashForCodeObject {
122  uint32_t operator () (void* code) const {
123    static const uintptr_t kGoldenRatio = 2654435761u;
124    uintptr_t hash = reinterpret_cast<uintptr_t>(code);
125    return static_cast<uint32_t>(hash * kGoldenRatio);
126  }
127};
128
129#ifdef WIN32
130typedef hash_map<void*, void*> JitInfoMap;
131#else
132typedef hash_map<void*, void*, HashForCodeObject, SameCodeObjects> JitInfoMap;
133#endif
134
135static JitInfoMap* GetEntries() {
136  static JitInfoMap* entries;
137  if (entries == NULL) {
138    entries = new JitInfoMap();
139  }
140  return entries;
141}
142
143static bool IsLineInfoTagged(void* ptr) {
144  return 0 != (reinterpret_cast<intptr_t>(ptr));
145}
146
147static JITCodeLineInfo* UntagLineInfo(void* ptr) {
148  return reinterpret_cast<JITCodeLineInfo*>(
149    reinterpret_cast<intptr_t>(ptr));
150}
151
152// The parameter str is a mixed pattern which contains the
153// function name and some other info. It comes from all the
154// Logger::CodeCreateEvent(...) function. This funtion get the
155// pure function name from the input parameter.
156static char* GetFunctionNameFromMixedName(const char* str, int length) {
157  int index = 0;
158  int count = 0;
159  char* start_ptr = NULL;
160
161  while (str[index++] != ':' && (index < length)) {}
162
163  if (str[index] == '*' || str[index] == '~' ) index++;
164  if (index >= length) return NULL;
165
166  start_ptr = const_cast<char*>(str + index);
167
168  while (index < length && str[index++] != ' ') {
169    count++;
170  }
171
172  char* result = new char[count + 1];
173  memcpy(result, start_ptr, count);
174  result[count] = '\0';
175
176  return result;
177}
178
179// The JitCodeEventHandler for Vtune.
180void VTUNEJITInterface::event_handler(const v8::JitCodeEvent* event) {
181  if (VTUNERUNNING && event != NULL) {
182    switch (event->type) {
183      case v8::JitCodeEvent::CODE_ADDED: {
184        char* temp_file_name = NULL;
185        char* temp_method_name =
186            GetFunctionNameFromMixedName(event->name.str,
187                                         static_cast<int>(event->name.len));
188        iJIT_Method_Load jmethod;
189        memset(&jmethod, 0, sizeof jmethod);
190        jmethod.method_id = iJIT_GetNewMethodID();
191        jmethod.method_load_address = event->code_start;
192        jmethod.method_size = static_cast<unsigned int>(event->code_len);
193        jmethod.method_name = temp_method_name;
194
195        Handle<UnboundScript> script = event->script;
196
197        if (*script != NULL) {
198          // Get the source file name and set it to jmethod.source_file_name
199          if ((*script->GetScriptName())->IsString()) {
200            Handle<String> script_name = script->GetScriptName()->ToString();
201            temp_file_name = new char[script_name->Utf8Length() + 1];
202            script_name->WriteUtf8(temp_file_name);
203            jmethod.source_file_name = temp_file_name;
204          }
205
206          JitInfoMap::iterator entry =
207              GetEntries()->find(event->code_start);
208          if (entry != GetEntries()->end() && IsLineInfoTagged(entry->first)) {
209            JITCodeLineInfo* line_info = UntagLineInfo(entry->second);
210            // Get the line_num_info and set it to jmethod.line_number_table
211            std::list<JITCodeLineInfo::LineNumInfo>* vtunelineinfo =
212                line_info->GetLineNumInfo();
213
214            jmethod.line_number_size = (unsigned int)vtunelineinfo->size();
215            jmethod.line_number_table =
216                reinterpret_cast<LineNumberInfo*>(
217                    malloc(sizeof(LineNumberInfo)*jmethod.line_number_size));
218
219            std::list<JITCodeLineInfo::LineNumInfo>::iterator Iter;
220            int index = 0;
221            for (Iter = vtunelineinfo->begin();
222                 Iter != vtunelineinfo->end();
223                 Iter++) {
224              jmethod.line_number_table[index].Offset =
225                  static_cast<unsigned int>(Iter->pc_);
226              jmethod.line_number_table[index++].LineNumber =
227                  script->GetLineNumber(Iter->pos_) + 1;
228            }
229            GetEntries()->erase(event->code_start);
230          }
231        }
232
233        iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED,
234                         reinterpret_cast<void*>(&jmethod));
235        if (temp_method_name)
236          delete []temp_method_name;
237        if (temp_file_name)
238          delete []temp_file_name;
239        break;
240      }
241      // TODO(chunyang.dai@intel.com): code_move will be supported.
242      case v8::JitCodeEvent::CODE_MOVED:
243        break;
244      // Currently the CODE_REMOVED event is not issued.
245      case v8::JitCodeEvent::CODE_REMOVED:
246        break;
247      case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: {
248        JITCodeLineInfo* line_info =
249            reinterpret_cast<JITCodeLineInfo*>(event->user_data);
250        if (line_info != NULL) {
251          line_info->SetPosition(static_cast<intptr_t>(event->line_info.offset),
252                                 static_cast<int>(event->line_info.pos));
253        }
254        break;
255      }
256      case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: {
257        v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event);
258        temp_event->user_data = new JITCodeLineInfo();
259        break;
260      }
261      case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: {
262        GetEntries()->insert(std::pair <void*, void*>(event->code_start, event->user_data));
263        break;
264      }
265      default:
266        break;
267    }
268  }
269  return;
270}
271
272}  // namespace internal
273
274void InitializeVtuneForV8(v8::Isolate::CreateParams& params) {
275  v8::V8::SetFlagsFromString("--nocompact_code_space",
276                             (int)strlen("--nocompact_code_space"));
277  params.code_event_handler = vTune::internal::VTUNEJITInterface::event_handler;
278}
279
280}  // namespace vTune
281