OLD | NEW |
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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 using v8::Object; | 44 using v8::Object; |
45 using v8::Script; | 45 using v8::Script; |
46 using v8::String; | 46 using v8::String; |
47 using v8::Value; | 47 using v8::Value; |
48 | 48 |
49 using v8::internal::byte; | 49 using v8::internal::byte; |
50 using v8::internal::Address; | 50 using v8::internal::Address; |
51 using v8::internal::Handle; | 51 using v8::internal::Handle; |
52 using v8::internal::Isolate; | 52 using v8::internal::Isolate; |
53 using v8::internal::JSFunction; | 53 using v8::internal::JSFunction; |
54 using v8::internal::StackTracer; | |
55 using v8::internal::TickSample; | 54 using v8::internal::TickSample; |
56 | 55 |
57 | 56 |
58 static struct { | 57 static struct { |
59 TickSample* sample; | 58 TickSample* sample; |
60 } trace_env = { NULL }; | 59 } trace_env = { NULL }; |
61 | 60 |
62 | 61 |
63 static void InitTraceEnv(TickSample* sample) { | 62 static void InitTraceEnv(TickSample* sample) { |
64 trace_env.sample = sample; | 63 trace_env.sample = sample; |
65 } | 64 } |
66 | 65 |
67 | 66 |
68 static void DoTrace(Address fp) { | 67 static void DoTrace(Address fp) { |
69 trace_env.sample->fp = fp; | 68 trace_env.sample->fp = fp; |
70 // sp is only used to define stack high bound | 69 // sp is only used to define stack high bound |
71 trace_env.sample->sp = | 70 trace_env.sample->sp = |
72 reinterpret_cast<Address>(trace_env.sample) - 10240; | 71 reinterpret_cast<Address>(trace_env.sample) - 10240; |
73 StackTracer::Trace(Isolate::Current(), trace_env.sample); | 72 trace_env.sample->Trace(Isolate::Current()); |
74 } | 73 } |
75 | 74 |
76 | 75 |
77 // Hide c_entry_fp to emulate situation when sampling is done while | 76 // Hide c_entry_fp to emulate situation when sampling is done while |
78 // pure JS code is being executed | 77 // pure JS code is being executed |
79 static void DoTraceHideCEntryFPAddress(Address fp) { | 78 static void DoTraceHideCEntryFPAddress(Address fp) { |
80 v8::internal::Address saved_c_frame_fp = | 79 v8::internal::Address saved_c_frame_fp = |
81 *(Isolate::Current()->c_entry_fp_address()); | 80 *(Isolate::Current()->c_entry_fp_address()); |
82 CHECK(saved_c_frame_fp); | 81 CHECK(saved_c_frame_fp); |
83 *(Isolate::Current()->c_entry_fp_address()) = 0; | 82 *(Isolate::Current()->c_entry_fp_address()) = 0; |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 // when called as a constructor. | 250 // when called as a constructor. |
252 CreateFramePointerGrabberConstructor("FPGrabber"); | 251 CreateFramePointerGrabberConstructor("FPGrabber"); |
253 | 252 |
254 // Compile the script. | 253 // Compile the script. |
255 CompileRun(trace_call_buf.start()); | 254 CompileRun(trace_call_buf.start()); |
256 } | 255 } |
257 | 256 |
258 | 257 |
259 // This test verifies that stack tracing works when called during | 258 // This test verifies that stack tracing works when called during |
260 // execution of a native function called from JS code. In this case, | 259 // execution of a native function called from JS code. In this case, |
261 // StackTracer uses Isolate::c_entry_fp as a starting point for stack | 260 // TickSample::Trace uses Isolate::c_entry_fp as a starting point for stack |
262 // walking. | 261 // walking. |
263 TEST(CFromJSStackTrace) { | 262 TEST(CFromJSStackTrace) { |
264 // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test. | 263 // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test. |
265 i::FLAG_use_inlining = false; | 264 i::FLAG_use_inlining = false; |
266 | 265 |
267 TickSample sample; | 266 TickSample sample; |
268 InitTraceEnv(&sample); | 267 InitTraceEnv(&sample); |
269 | 268 |
270 CcTest::InitializeVM(TRACE_EXTENSION); | 269 CcTest::InitializeVM(TRACE_EXTENSION); |
271 v8::HandleScope scope(CcTest::isolate()); | 270 v8::HandleScope scope(CcTest::isolate()); |
272 // Create global function JSFuncDoTrace which calls | 271 // Create global function JSFuncDoTrace which calls |
273 // extension function trace() with the current frame pointer value. | 272 // extension function trace() with the current frame pointer value. |
274 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); | 273 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); |
275 Local<Value> result = CompileRun( | 274 Local<Value> result = CompileRun( |
276 "function JSTrace() {" | 275 "function JSTrace() {" |
277 " JSFuncDoTrace();" | 276 " JSFuncDoTrace();" |
278 "};\n" | 277 "};\n" |
279 "JSTrace();\n" | 278 "JSTrace();\n" |
280 "true;"); | 279 "true;"); |
281 CHECK(!result.IsEmpty()); | 280 CHECK(!result.IsEmpty()); |
282 // When stack tracer is invoked, the stack should look as follows: | 281 // When stack tracer is invoked, the stack should look as follows: |
283 // script [JS] | 282 // script [JS] |
284 // JSTrace() [JS] | 283 // JSTrace() [JS] |
285 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] | 284 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] |
286 // trace(EBP) [native (extension)] | 285 // trace(EBP) [native (extension)] |
287 // DoTrace(EBP) [native] | 286 // DoTrace(EBP) [native] |
288 // StackTracer::Trace | 287 // TickSample::Trace |
289 | 288 |
290 CHECK(sample.external_callback); | 289 CHECK(sample.external_callback); |
291 CHECK_EQ(FUNCTION_ADDR(TraceExtension::Trace), sample.external_callback); | 290 CHECK_EQ(FUNCTION_ADDR(TraceExtension::Trace), sample.external_callback); |
292 | 291 |
293 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" | 292 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" |
294 int base = 0; | 293 int base = 0; |
295 CHECK_GT(sample.frames_count, base + 1); | 294 CHECK_GT(sample.frames_count, base + 1); |
296 | 295 |
297 CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0])); | 296 CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0])); |
298 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1])); | 297 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1])); |
299 } | 298 } |
300 | 299 |
301 | 300 |
302 // This test verifies that stack tracing works when called during | 301 // This test verifies that stack tracing works when called during |
303 // execution of JS code. However, as calling StackTracer requires | 302 // execution of JS code. However, as calling TickSample::Trace requires |
304 // entering native code, we can only emulate pure JS by erasing | 303 // entering native code, we can only emulate pure JS by erasing |
305 // Isolate::c_entry_fp value. In this case, StackTracer uses passed frame | 304 // Isolate::c_entry_fp value. In this case, TickSample::Trace uses passed frame |
306 // pointer value as a starting point for stack walking. | 305 // pointer value as a starting point for stack walking. |
307 TEST(PureJSStackTrace) { | 306 TEST(PureJSStackTrace) { |
308 // This test does not pass with inlining enabled since inlined functions | 307 // This test does not pass with inlining enabled since inlined functions |
309 // don't appear in the stack trace. | 308 // don't appear in the stack trace. |
310 i::FLAG_use_inlining = false; | 309 i::FLAG_use_inlining = false; |
311 | 310 |
312 TickSample sample; | 311 TickSample sample; |
313 InitTraceEnv(&sample); | 312 InitTraceEnv(&sample); |
314 | 313 |
315 CcTest::InitializeVM(TRACE_EXTENSION); | 314 CcTest::InitializeVM(TRACE_EXTENSION); |
(...skipping 11 matching lines...) Expand all Loading... |
327 "OuterJSTrace();\n" | 326 "OuterJSTrace();\n" |
328 "true;"); | 327 "true;"); |
329 CHECK(!result.IsEmpty()); | 328 CHECK(!result.IsEmpty()); |
330 // When stack tracer is invoked, the stack should look as follows: | 329 // When stack tracer is invoked, the stack should look as follows: |
331 // script [JS] | 330 // script [JS] |
332 // OuterJSTrace() [JS] | 331 // OuterJSTrace() [JS] |
333 // JSTrace() [JS] | 332 // JSTrace() [JS] |
334 // JSFuncDoTrace() [JS] | 333 // JSFuncDoTrace() [JS] |
335 // js_trace(EBP) [native (extension)] | 334 // js_trace(EBP) [native (extension)] |
336 // DoTraceHideCEntryFPAddress(EBP) [native] | 335 // DoTraceHideCEntryFPAddress(EBP) [native] |
337 // StackTracer::Trace | 336 // TickSample::Trace |
338 // | 337 // |
339 | 338 |
340 CHECK(sample.external_callback); | 339 CHECK(sample.external_callback); |
341 CHECK_EQ(FUNCTION_ADDR(TraceExtension::JSTrace), sample.external_callback); | 340 CHECK_EQ(FUNCTION_ADDR(TraceExtension::JSTrace), sample.external_callback); |
342 | 341 |
343 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" | 342 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" |
344 int base = 0; | 343 int base = 0; |
345 CHECK_GT(sample.frames_count, base + 1); | 344 CHECK_GT(sample.frames_count, base + 1); |
346 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 0])); | 345 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 0])); |
347 CHECK(IsAddressWithinFuncCode("OuterJSTrace", sample.stack[base + 1])); | 346 CHECK(IsAddressWithinFuncCode("OuterJSTrace", sample.stack[base + 1])); |
(...skipping 19 matching lines...) Expand all Loading... |
367 if (depth <= 0) { | 366 if (depth <= 0) { |
368 CFuncDoTrace(0); | 367 CFuncDoTrace(0); |
369 return 0; | 368 return 0; |
370 } else { | 369 } else { |
371 return CFunc(depth - 1) + 1; | 370 return CFunc(depth - 1) + 1; |
372 } | 371 } |
373 } | 372 } |
374 | 373 |
375 | 374 |
376 // This test verifies that stack tracing doesn't crash when called on | 375 // This test verifies that stack tracing doesn't crash when called on |
377 // pure native code. StackTracer only unrolls JS code, so we can't | 376 // pure native code. TickSample::Trace only unrolls JS code, so we can't |
378 // get any meaningful info here. | 377 // get any meaningful info here. |
379 TEST(PureCStackTrace) { | 378 TEST(PureCStackTrace) { |
380 TickSample sample; | 379 TickSample sample; |
381 InitTraceEnv(&sample); | 380 InitTraceEnv(&sample); |
382 CcTest::InitializeVM(TRACE_EXTENSION); | 381 CcTest::InitializeVM(TRACE_EXTENSION); |
383 // Check that sampler doesn't crash | 382 // Check that sampler doesn't crash |
384 CHECK_EQ(10, CFunc(10)); | 383 CHECK_EQ(10, CFunc(10)); |
385 } | 384 } |
386 | 385 |
387 | 386 |
388 TEST(JsEntrySp) { | 387 TEST(JsEntrySp) { |
389 CcTest::InitializeVM(TRACE_EXTENSION); | 388 CcTest::InitializeVM(TRACE_EXTENSION); |
390 v8::HandleScope scope(CcTest::isolate()); | 389 v8::HandleScope scope(CcTest::isolate()); |
391 CHECK_EQ(0, GetJsEntrySp()); | 390 CHECK_EQ(0, GetJsEntrySp()); |
392 CompileRun("a = 1; b = a + 1;"); | 391 CompileRun("a = 1; b = a + 1;"); |
393 CHECK_EQ(0, GetJsEntrySp()); | 392 CHECK_EQ(0, GetJsEntrySp()); |
394 CompileRun("js_entry_sp();"); | 393 CompileRun("js_entry_sp();"); |
395 CHECK_EQ(0, GetJsEntrySp()); | 394 CHECK_EQ(0, GetJsEntrySp()); |
396 CompileRun("js_entry_sp_level2();"); | 395 CompileRun("js_entry_sp_level2();"); |
397 CHECK_EQ(0, GetJsEntrySp()); | 396 CHECK_EQ(0, GetJsEntrySp()); |
398 } | 397 } |
OLD | NEW |