The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / test / cctest / test-log-ia32.cc @ 40c0f755

History | View | Annotate | Download (8.57 KB)

1
// Copyright 2006-2009 the V8 project authors. All rights reserved.
2
//
3
// Tests of profiler-related functions from log.h
4

    
5
#ifdef ENABLE_LOGGING_AND_PROFILING
6

    
7
#include <stdlib.h>
8

    
9
#include "v8.h"
10

    
11
#include "log.h"
12
#include "top.h"
13
#include "cctest.h"
14

    
15
using v8::Function;
16
using v8::Local;
17
using v8::Object;
18
using v8::Script;
19
using v8::String;
20
using v8::Value;
21

    
22
using v8::internal::byte;
23
using v8::internal::Handle;
24
using v8::internal::JSFunction;
25
using v8::internal::StackTracer;
26
using v8::internal::TickSample;
27
using v8::internal::Top;
28

    
29

    
30
static v8::Persistent<v8::Context> env;
31

    
32

    
33
static struct {
34
  StackTracer* tracer;
35
  TickSample* sample;
36
} trace_env = { NULL, NULL };
37

    
38

    
39
static void InitTraceEnv(StackTracer* tracer, TickSample* sample) {
40
  trace_env.tracer = tracer;
41
  trace_env.sample = sample;
42
}
43

    
44

    
45
static void DoTrace(unsigned int fp) {
46
  trace_env.sample->fp = fp;
47
  // sp is only used to define stack high bound
48
  trace_env.sample->sp =
49
      reinterpret_cast<unsigned int>(trace_env.sample) - 10240;
50
  trace_env.tracer->Trace(trace_env.sample);
51
}
52

    
53

    
54
// Hide c_entry_fp to emulate situation when sampling is done while
55
// pure JS code is being executed
56
static void DoTraceHideCEntryFPAddress(unsigned int fp) {
57
  v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address());
58
  CHECK(saved_c_frame_fp);
59
  *(Top::c_entry_fp_address()) = 0;
60
  DoTrace(fp);
61
  *(Top::c_entry_fp_address()) = saved_c_frame_fp;
62
}
63

    
64

    
65
static void CheckRetAddrIsInFunction(const char* func_name,
66
                                     unsigned int ret_addr,
67
                                     unsigned int func_start_addr,
68
                                     unsigned int func_len) {
69
  printf("CheckRetAddrIsInFunction \"%s\": %08x %08x %08x\n",
70
         func_name, func_start_addr, ret_addr, func_start_addr + func_len);
71
  CHECK_GE(ret_addr, func_start_addr);
72
  CHECK_GE(func_start_addr + func_len, ret_addr);
73
}
74

    
75

    
76
static void CheckRetAddrIsInJSFunction(const char* func_name,
77
                                       unsigned int ret_addr,
78
                                       Handle<JSFunction> func) {
79
  v8::internal::Code* func_code = func->code();
80
  CheckRetAddrIsInFunction(
81
      func_name, ret_addr,
82
      reinterpret_cast<unsigned int>(func_code->instruction_start()),
83
      func_code->ExecutableSize());
84
}
85

    
86

    
87
// --- T r a c e   E x t e n s i o n ---
88

    
89
class TraceExtension : public v8::Extension {
90
 public:
91
  TraceExtension() : v8::Extension("v8/trace", kSource) { }
92
  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
93
      v8::Handle<String> name);
94
  static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
95
  static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
96
 private:
97
  static unsigned int GetFP(const v8::Arguments& args);
98
  static const char* kSource;
99
};
100

    
101

    
102
const char* TraceExtension::kSource =
103
    "native function trace();"
104
    "native function js_trace();";
105

    
106

    
107
v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
108
    v8::Handle<String> name) {
109
  if (name->Equals(String::New("trace"))) {
110
    return v8::FunctionTemplate::New(TraceExtension::Trace);
111
  } else if (name->Equals(String::New("js_trace"))) {
112
    return v8::FunctionTemplate::New(TraceExtension::JSTrace);
113
  } else {
114
    CHECK(false);
115
    return v8::Handle<v8::FunctionTemplate>();
116
  }
117
}
118

    
119

    
120
unsigned int TraceExtension::GetFP(const v8::Arguments& args) {
121
  CHECK_EQ(1, args.Length());
122
  unsigned int fp = args[0]->Int32Value() << 2;
123
  printf("Trace: %08x\n", fp);
124
  return fp;
125
}
126

    
127

    
128
v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
129
  DoTrace(GetFP(args));
130
  return v8::Undefined();
131
}
132

    
133

    
134
v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
135
  DoTraceHideCEntryFPAddress(GetFP(args));
136
  return v8::Undefined();
137
}
138

    
139

    
140
static TraceExtension kTraceExtension;
141
v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
142

    
143

    
144
static void InitializeVM() {
145
  if (env.IsEmpty()) {
146
    v8::HandleScope scope;
147
    const char* extensions[] = { "v8/trace" };
148
    v8::ExtensionConfiguration config(1, extensions);
149
    env = v8::Context::New(&config);
150
  }
151
  v8::HandleScope scope;
152
  env->Enter();
153
}
154

    
155

    
156
static Handle<JSFunction> CompileFunction(const char* source) {
157
  return v8::Utils::OpenHandle(*Script::Compile(String::New(source)));
158
}
159

    
160

    
161
static void CompileRun(const char* source) {
162
  Script::Compile(String::New(source))->Run();
163
}
164

    
165

    
166
static Local<Value> GetGlobalProperty(const char* name) {
167
  return env->Global()->Get(String::New(name));
168
}
169

    
170

    
171
static Handle<JSFunction> GetGlobalJSFunction(const char* name) {
172
  Handle<JSFunction> js_func(JSFunction::cast(
173
                                 *(v8::Utils::OpenHandle(
174
                                       *GetGlobalProperty(name)))));
175
  return js_func;
176
}
177

    
178

    
179
static void CheckRetAddrIsInJSFunction(const char* func_name,
180
                                       unsigned int ret_addr) {
181
  CheckRetAddrIsInJSFunction(func_name, ret_addr,
182
                             GetGlobalJSFunction(func_name));
183
}
184

    
185

    
186
static void SetGlobalProperty(const char* name, Local<Value> value) {
187
  env->Global()->Set(String::New(name), value);
188
}
189

    
190

    
191
static bool Patch(byte* from,
192
                  size_t num,
193
                  byte* original,
194
                  byte* patch,
195
                  size_t patch_len) {
196
  byte* to = from + num;
197
  do {
198
    from = static_cast<byte*>(memchr(from, *original, to - from));
199
    CHECK(from != NULL);
200
    if (memcmp(original, from, patch_len) == 0) {
201
      memcpy(from, patch, patch_len);
202
      return true;
203
    } else {
204
      from++;
205
    }
206
  } while (to - from > 0);
207
  return false;
208
}
209

    
210

    
211
// Creates a global function named 'func_name' that calls the tracing
212
// function 'trace_func_name' with an actual EBP register value,
213
// shifted right to be presented as Smi.
214
static void CreateTraceCallerFunction(const char* func_name,
215
                                      const char* trace_func_name) {
216
  ::v8::internal::EmbeddedVector<char, 256> trace_call_buf;
217
  ::v8::internal::OS::SNPrintF(trace_call_buf, "%s(0x6666);", trace_func_name);
218
  Handle<JSFunction> func = CompileFunction(trace_call_buf.start());
219
  CHECK(!func.is_null());
220
  v8::internal::Code* func_code = func->code();
221
  CHECK(func_code->IsCode());
222

    
223
  // push 0xcccc (= 0x6666 << 1)
224
  byte original[] = { 0x68, 0xcc, 0xcc, 0x00, 0x00 };
225
  // mov eax,ebp; shr eax; push eax;
226
  byte patch[] = { 0x89, 0xe8, 0xd1, 0xe8, 0x50 };
227
  // Patch generated code to replace pushing of a constant with
228
  // pushing of ebp contents in a Smi
229
  CHECK(Patch(func_code->instruction_start(),
230
              func_code->instruction_size(),
231
              original, patch, sizeof(patch)));
232

    
233
  SetGlobalProperty(func_name, v8::ToApi<Value>(func));
234
}
235

    
236

    
237
TEST(CFromJSStackTrace) {
238
  TickSample sample;
239
  StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
240
  InitTraceEnv(&tracer, &sample);
241

    
242
  InitializeVM();
243
  v8::HandleScope scope;
244
  CreateTraceCallerFunction("JSFuncDoTrace", "trace");
245
  CompileRun(
246
      "function JSTrace() {"
247
      "  JSFuncDoTrace();"
248
      "};\n"
249
      "JSTrace();");
250
  CHECK_GT(sample.frames_count, 1);
251
  // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace"
252
  CheckRetAddrIsInJSFunction("JSFuncDoTrace",
253
                             reinterpret_cast<unsigned int>(sample.stack[0]));
254
  CheckRetAddrIsInJSFunction("JSTrace",
255
                             reinterpret_cast<unsigned int>(sample.stack[1]));
256
}
257

    
258

    
259
TEST(PureJSStackTrace) {
260
  TickSample sample;
261
  StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
262
  InitTraceEnv(&tracer, &sample);
263

    
264
  InitializeVM();
265
  v8::HandleScope scope;
266
  CreateTraceCallerFunction("JSFuncDoTrace", "js_trace");
267
  CompileRun(
268
      "function JSTrace() {"
269
      "  JSFuncDoTrace();"
270
      "};\n"
271
      "function OuterJSTrace() {"
272
      "  JSTrace();"
273
      "};\n"
274
      "OuterJSTrace();");
275
  CHECK_GT(sample.frames_count, 1);
276
  // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
277
  CheckRetAddrIsInJSFunction("JSTrace",
278
                             reinterpret_cast<unsigned int>(sample.stack[0]));
279
  CheckRetAddrIsInJSFunction("OuterJSTrace",
280
                             reinterpret_cast<unsigned int>(sample.stack[1]));
281
}
282

    
283

    
284
static void CFuncDoTrace() {
285
  unsigned int fp;
286
#ifdef __GNUC__
287
  fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0));
288
#elif defined _MSC_VER
289
  __asm mov [fp], ebp  // NOLINT
290
#endif
291
  DoTrace(fp);
292
}
293

    
294

    
295
static int CFunc(int depth) {
296
  if (depth <= 0) {
297
    CFuncDoTrace();
298
    return 0;
299
  } else {
300
    return CFunc(depth - 1) + 1;
301
  }
302
}
303

    
304

    
305
TEST(PureCStackTrace) {
306
  TickSample sample;
307
  StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
308
  InitTraceEnv(&tracer, &sample);
309
  // Check that sampler doesn't crash
310
  CHECK_EQ(10, CFunc(10));
311
}
312

    
313

    
314
#endif  // ENABLE_LOGGING_AND_PROFILING