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 40c0f755 Ryan
// 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