Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(5)

Side by Side Diff: test/cctest/test-log-stack-tracer.cc

Issue 130213009: Various extension-related cleanup and simplifications. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Whitespace Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « test/cctest/test-heap-profiler.cc ('k') | test/cctest/test-profile-generator.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 20 matching lines...) Expand all
31 31
32 #include "v8.h" 32 #include "v8.h"
33 33
34 #include "api.h" 34 #include "api.h"
35 #include "cctest.h" 35 #include "cctest.h"
36 #include "codegen.h" 36 #include "codegen.h"
37 #include "disassembler.h" 37 #include "disassembler.h"
38 #include "isolate.h" 38 #include "isolate.h"
39 #include "log.h" 39 #include "log.h"
40 #include "sampler.h" 40 #include "sampler.h"
41 #include "trace-extension.h"
41 #include "vm-state-inl.h" 42 #include "vm-state-inl.h"
42 43
43 using v8::Function; 44 using v8::Function;
44 using v8::Local; 45 using v8::Local;
45 using v8::Object; 46 using v8::Object;
46 using v8::Script; 47 using v8::Script;
47 using v8::String; 48 using v8::String;
48 using v8::Value; 49 using v8::Value;
49 50
50 using v8::internal::byte; 51 using v8::internal::byte;
51 using v8::internal::Address; 52 using v8::internal::Address;
52 using v8::internal::Handle; 53 using v8::internal::Handle;
53 using v8::internal::Isolate; 54 using v8::internal::Isolate;
54 using v8::internal::JSFunction; 55 using v8::internal::JSFunction;
55 using v8::internal::RegisterState;
56 using v8::internal::TickSample; 56 using v8::internal::TickSample;
57 57
58 58
59 static struct {
60 TickSample* sample;
61 } trace_env = { NULL };
62
63
64 static void InitTraceEnv(TickSample* sample) {
65 trace_env.sample = sample;
66 }
67
68
69 static void DoTrace(Address fp) {
70 RegisterState regs;
71 regs.fp = fp;
72 // sp is only used to define stack high bound
73 regs.sp =
74 reinterpret_cast<Address>(trace_env.sample) - 10240;
75 trace_env.sample->Init(CcTest::i_isolate(), regs);
76 }
77
78
79 // Hide c_entry_fp to emulate situation when sampling is done while
80 // pure JS code is being executed
81 static void DoTraceHideCEntryFPAddress(Address fp) {
82 v8::internal::Address saved_c_frame_fp =
83 *(CcTest::i_isolate()->c_entry_fp_address());
84 CHECK(saved_c_frame_fp);
85 *(CcTest::i_isolate()->c_entry_fp_address()) = 0;
86 DoTrace(fp);
87 *(CcTest::i_isolate()->c_entry_fp_address()) = saved_c_frame_fp;
88 }
89
90
91 // --- T r a c e E x t e n s i o n ---
92
93 class TraceExtension : public v8::Extension {
94 public:
95 TraceExtension() : v8::Extension("v8/trace", kSource) { }
96 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunctionTemplate(
97 v8::Isolate* isolate,
98 v8::Handle<String> name);
99 static void Trace(const v8::FunctionCallbackInfo<v8::Value>& args);
100 static void JSTrace(const v8::FunctionCallbackInfo<v8::Value>& args);
101 static void JSEntrySP(const v8::FunctionCallbackInfo<v8::Value>& args);
102 static void JSEntrySPLevel2(const v8::FunctionCallbackInfo<v8::Value>& args);
103 private:
104 static Address GetFP(const v8::FunctionCallbackInfo<v8::Value>& args);
105 static const char* kSource;
106 };
107
108
109 const char* TraceExtension::kSource =
110 "native function trace();"
111 "native function js_trace();"
112 "native function js_entry_sp();"
113 "native function js_entry_sp_level2();";
114
115 v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunctionTemplate(
116 v8::Isolate* isolate, v8::Handle<String> name) {
117 if (name->Equals(String::NewFromUtf8(isolate, "trace"))) {
118 return v8::FunctionTemplate::New(isolate, TraceExtension::Trace);
119 } else if (name->Equals(
120 String::NewFromUtf8(isolate, "js_trace"))) {
121 return v8::FunctionTemplate::New(isolate, TraceExtension::JSTrace);
122 } else if (name->Equals(String::NewFromUtf8(isolate, "js_entry_sp"))) {
123 return v8::FunctionTemplate::New(isolate, TraceExtension::JSEntrySP);
124 } else if (name->Equals(String::NewFromUtf8(isolate, "js_entry_sp_level2"))) {
125 return v8::FunctionTemplate::New(isolate, TraceExtension::JSEntrySPLevel2);
126 } else {
127 CHECK(false);
128 return v8::Handle<v8::FunctionTemplate>();
129 }
130 }
131
132
133 Address TraceExtension::GetFP(const v8::FunctionCallbackInfo<v8::Value>& args) {
134 // Convert frame pointer from encoding as smis in the arguments to a pointer.
135 CHECK_EQ(2, args.Length()); // Ignore second argument on 32-bit platform.
136 #if defined(V8_HOST_ARCH_32_BIT)
137 Address fp = *reinterpret_cast<Address*>(*args[0]);
138 #elif defined(V8_HOST_ARCH_64_BIT)
139 int64_t low_bits = *reinterpret_cast<uint64_t*>(*args[0]) >> 32;
140 int64_t high_bits = *reinterpret_cast<uint64_t*>(*args[1]);
141 Address fp = reinterpret_cast<Address>(high_bits | low_bits);
142 #else
143 #error Host architecture is neither 32-bit nor 64-bit.
144 #endif
145 printf("Trace: %p\n", fp);
146 return fp;
147 }
148
149
150 void TraceExtension::Trace(const v8::FunctionCallbackInfo<v8::Value>& args) {
151 DoTrace(GetFP(args));
152 }
153
154
155 void TraceExtension::JSTrace(const v8::FunctionCallbackInfo<v8::Value>& args) {
156 DoTraceHideCEntryFPAddress(GetFP(args));
157 }
158
159
160 static Address GetJsEntrySp() {
161 CHECK_NE(NULL, CcTest::i_isolate()->thread_local_top());
162 return CcTest::i_isolate()->js_entry_sp();
163 }
164
165
166 void TraceExtension::JSEntrySP(
167 const v8::FunctionCallbackInfo<v8::Value>& args) {
168 CHECK_NE(0, GetJsEntrySp());
169 }
170
171
172 void TraceExtension::JSEntrySPLevel2(
173 const v8::FunctionCallbackInfo<v8::Value>& args) {
174 v8::HandleScope scope(args.GetIsolate());
175 const Address js_entry_sp = GetJsEntrySp();
176 CHECK_NE(0, js_entry_sp);
177 CompileRun("js_entry_sp();");
178 CHECK_EQ(js_entry_sp, GetJsEntrySp());
179 }
180
181
182 static TraceExtension kTraceExtension;
183 v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
184
185
186 static bool IsAddressWithinFuncCode(JSFunction* function, Address addr) { 59 static bool IsAddressWithinFuncCode(JSFunction* function, Address addr) {
187 i::Code* code = function->code(); 60 i::Code* code = function->code();
188 return code->contains(addr); 61 return code->contains(addr);
189 } 62 }
190 63
191 64
192 static bool IsAddressWithinFuncCode(v8::Local<v8::Context> context, 65 static bool IsAddressWithinFuncCode(v8::Local<v8::Context> context,
193 const char* func_name, 66 const char* func_name,
194 Address addr) { 67 Address addr) {
195 v8::Local<v8::Value> func = context->Global()->Get(v8_str(func_name)); 68 v8::Local<v8::Value> func = context->Global()->Get(v8_str(func_name));
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 137
265 // This test verifies that stack tracing works when called during 138 // This test verifies that stack tracing works when called during
266 // execution of a native function called from JS code. In this case, 139 // execution of a native function called from JS code. In this case,
267 // TickSample::Trace uses Isolate::c_entry_fp as a starting point for stack 140 // TickSample::Trace uses Isolate::c_entry_fp as a starting point for stack
268 // walking. 141 // walking.
269 TEST(CFromJSStackTrace) { 142 TEST(CFromJSStackTrace) {
270 // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test. 143 // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test.
271 i::FLAG_use_inlining = false; 144 i::FLAG_use_inlining = false;
272 145
273 TickSample sample; 146 TickSample sample;
274 InitTraceEnv(&sample); 147 i::TraceExtension::InitTraceEnv(&sample);
275 148
276 v8::HandleScope scope(CcTest::isolate()); 149 v8::HandleScope scope(CcTest::isolate());
277 v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION); 150 v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
278 v8::Context::Scope context_scope(context); 151 v8::Context::Scope context_scope(context);
279 152
280 // Create global function JSFuncDoTrace which calls 153 // Create global function JSFuncDoTrace which calls
281 // extension function trace() with the current frame pointer value. 154 // extension function trace() with the current frame pointer value.
282 CreateTraceCallerFunction(context, "JSFuncDoTrace", "trace"); 155 CreateTraceCallerFunction(context, "JSFuncDoTrace", "trace");
283 Local<Value> result = CompileRun( 156 Local<Value> result = CompileRun(
284 "function JSTrace() {" 157 "function JSTrace() {"
285 " JSFuncDoTrace();" 158 " JSFuncDoTrace();"
286 "};\n" 159 "};\n"
287 "JSTrace();\n" 160 "JSTrace();\n"
288 "true;"); 161 "true;");
289 CHECK(!result.IsEmpty()); 162 CHECK(!result.IsEmpty());
290 // When stack tracer is invoked, the stack should look as follows: 163 // When stack tracer is invoked, the stack should look as follows:
291 // script [JS] 164 // script [JS]
292 // JSTrace() [JS] 165 // JSTrace() [JS]
293 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] 166 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi]
294 // trace(EBP) [native (extension)] 167 // trace(EBP) [native (extension)]
295 // DoTrace(EBP) [native] 168 // DoTrace(EBP) [native]
296 // TickSample::Trace 169 // TickSample::Trace
297 170
298 CHECK(sample.has_external_callback); 171 CHECK(sample.has_external_callback);
299 CHECK_EQ(FUNCTION_ADDR(TraceExtension::Trace), sample.external_callback); 172 CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::Trace), sample.external_callback);
300 173
301 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" 174 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
302 int base = 0; 175 int base = 0;
303 CHECK_GT(sample.frames_count, base + 1); 176 CHECK_GT(sample.frames_count, base + 1);
304 177
305 CHECK(IsAddressWithinFuncCode( 178 CHECK(IsAddressWithinFuncCode(
306 context, "JSFuncDoTrace", sample.stack[base + 0])); 179 context, "JSFuncDoTrace", sample.stack[base + 0]));
307 CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 1])); 180 CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 1]));
308 } 181 }
309 182
310 183
311 // This test verifies that stack tracing works when called during 184 // This test verifies that stack tracing works when called during
312 // execution of JS code. However, as calling TickSample::Trace requires 185 // execution of JS code. However, as calling TickSample::Trace requires
313 // entering native code, we can only emulate pure JS by erasing 186 // entering native code, we can only emulate pure JS by erasing
314 // Isolate::c_entry_fp value. In this case, TickSample::Trace uses passed frame 187 // Isolate::c_entry_fp value. In this case, TickSample::Trace uses passed frame
315 // pointer value as a starting point for stack walking. 188 // pointer value as a starting point for stack walking.
316 TEST(PureJSStackTrace) { 189 TEST(PureJSStackTrace) {
317 // This test does not pass with inlining enabled since inlined functions 190 // This test does not pass with inlining enabled since inlined functions
318 // don't appear in the stack trace. 191 // don't appear in the stack trace.
319 i::FLAG_use_inlining = false; 192 i::FLAG_use_inlining = false;
320 193
321 TickSample sample; 194 TickSample sample;
322 InitTraceEnv(&sample); 195 i::TraceExtension::InitTraceEnv(&sample);
323 196
324 v8::HandleScope scope(CcTest::isolate()); 197 v8::HandleScope scope(CcTest::isolate());
325 v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION); 198 v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
326 v8::Context::Scope context_scope(context); 199 v8::Context::Scope context_scope(context);
327 200
328 // Create global function JSFuncDoTrace which calls 201 // Create global function JSFuncDoTrace which calls
329 // extension function js_trace() with the current frame pointer value. 202 // extension function js_trace() with the current frame pointer value.
330 CreateTraceCallerFunction(context, "JSFuncDoTrace", "js_trace"); 203 CreateTraceCallerFunction(context, "JSFuncDoTrace", "js_trace");
331 Local<Value> result = CompileRun( 204 Local<Value> result = CompileRun(
332 "function JSTrace() {" 205 "function JSTrace() {"
333 " JSFuncDoTrace();" 206 " JSFuncDoTrace();"
334 "};\n" 207 "};\n"
335 "function OuterJSTrace() {" 208 "function OuterJSTrace() {"
336 " JSTrace();" 209 " JSTrace();"
337 "};\n" 210 "};\n"
338 "OuterJSTrace();\n" 211 "OuterJSTrace();\n"
339 "true;"); 212 "true;");
340 CHECK(!result.IsEmpty()); 213 CHECK(!result.IsEmpty());
341 // When stack tracer is invoked, the stack should look as follows: 214 // When stack tracer is invoked, the stack should look as follows:
342 // script [JS] 215 // script [JS]
343 // OuterJSTrace() [JS] 216 // OuterJSTrace() [JS]
344 // JSTrace() [JS] 217 // JSTrace() [JS]
345 // JSFuncDoTrace() [JS] 218 // JSFuncDoTrace() [JS]
346 // js_trace(EBP) [native (extension)] 219 // js_trace(EBP) [native (extension)]
347 // DoTraceHideCEntryFPAddress(EBP) [native] 220 // DoTraceHideCEntryFPAddress(EBP) [native]
348 // TickSample::Trace 221 // TickSample::Trace
349 // 222 //
350 223
351 CHECK(sample.has_external_callback); 224 CHECK(sample.has_external_callback);
352 CHECK_EQ(FUNCTION_ADDR(TraceExtension::JSTrace), sample.external_callback); 225 CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::JSTrace), sample.external_callback);
353 226
354 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" 227 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
355 int base = 0; 228 int base = 0;
356 CHECK_GT(sample.frames_count, base + 1); 229 CHECK_GT(sample.frames_count, base + 1);
357 CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 0])); 230 CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 0]));
358 CHECK(IsAddressWithinFuncCode( 231 CHECK(IsAddressWithinFuncCode(
359 context, "OuterJSTrace", sample.stack[base + 1])); 232 context, "OuterJSTrace", sample.stack[base + 1]));
360 } 233 }
361 234
362 235
363 static void CFuncDoTrace(byte dummy_parameter) { 236 static void CFuncDoTrace(byte dummy_parameter) {
364 Address fp; 237 Address fp;
365 #ifdef __GNUC__ 238 #ifdef __GNUC__
366 fp = reinterpret_cast<Address>(__builtin_frame_address(0)); 239 fp = reinterpret_cast<Address>(__builtin_frame_address(0));
367 #elif defined _MSC_VER 240 #elif defined _MSC_VER
368 // Approximate a frame pointer address. We compile without base pointers, 241 // Approximate a frame pointer address. We compile without base pointers,
369 // so we can't trust ebp/rbp. 242 // so we can't trust ebp/rbp.
370 fp = &dummy_parameter - 2 * sizeof(void*); // NOLINT 243 fp = &dummy_parameter - 2 * sizeof(void*); // NOLINT
371 #else 244 #else
372 #error Unexpected platform. 245 #error Unexpected platform.
373 #endif 246 #endif
374 DoTrace(fp); 247 i::TraceExtension::DoTrace(fp);
375 } 248 }
376 249
377 250
378 static int CFunc(int depth) { 251 static int CFunc(int depth) {
379 if (depth <= 0) { 252 if (depth <= 0) {
380 CFuncDoTrace(0); 253 CFuncDoTrace(0);
381 return 0; 254 return 0;
382 } else { 255 } else {
383 return CFunc(depth - 1) + 1; 256 return CFunc(depth - 1) + 1;
384 } 257 }
385 } 258 }
386 259
387 260
388 // This test verifies that stack tracing doesn't crash when called on 261 // This test verifies that stack tracing doesn't crash when called on
389 // pure native code. TickSample::Trace only unrolls JS code, so we can't 262 // pure native code. TickSample::Trace only unrolls JS code, so we can't
390 // get any meaningful info here. 263 // get any meaningful info here.
391 TEST(PureCStackTrace) { 264 TEST(PureCStackTrace) {
392 TickSample sample; 265 TickSample sample;
393 InitTraceEnv(&sample); 266 i::TraceExtension::InitTraceEnv(&sample);
394 v8::HandleScope scope(CcTest::isolate()); 267 v8::HandleScope scope(CcTest::isolate());
395 v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION); 268 v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
396 v8::Context::Scope context_scope(context); 269 v8::Context::Scope context_scope(context);
397 // Check that sampler doesn't crash 270 // Check that sampler doesn't crash
398 CHECK_EQ(10, CFunc(10)); 271 CHECK_EQ(10, CFunc(10));
399 } 272 }
400 273
401 274
402 TEST(JsEntrySp) { 275 TEST(JsEntrySp) {
403 v8::HandleScope scope(CcTest::isolate()); 276 v8::HandleScope scope(CcTest::isolate());
404 v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION); 277 v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
405 v8::Context::Scope context_scope(context); 278 v8::Context::Scope context_scope(context);
406 CHECK_EQ(0, GetJsEntrySp()); 279 CHECK_EQ(0, i::TraceExtension::GetJsEntrySp());
407 CompileRun("a = 1; b = a + 1;"); 280 CompileRun("a = 1; b = a + 1;");
408 CHECK_EQ(0, GetJsEntrySp()); 281 CHECK_EQ(0, i::TraceExtension::GetJsEntrySp());
409 CompileRun("js_entry_sp();"); 282 CompileRun("js_entry_sp();");
410 CHECK_EQ(0, GetJsEntrySp()); 283 CHECK_EQ(0, i::TraceExtension::GetJsEntrySp());
411 CompileRun("js_entry_sp_level2();"); 284 CompileRun("js_entry_sp_level2();");
412 CHECK_EQ(0, GetJsEntrySp()); 285 CHECK_EQ(0, i::TraceExtension::GetJsEntrySp());
413 } 286 }
OLDNEW
« no previous file with comments | « test/cctest/test-heap-profiler.cc ('k') | test/cctest/test-profile-generator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698