| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Tests of profiler-related functions from log.h | 3 // Tests of profiler-related functions from log.h |
| 4 | 4 |
| 5 #ifdef ENABLE_LOGGING_AND_PROFILING | 5 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 6 | 6 |
| 7 #include <stdlib.h> | 7 #include <stdlib.h> |
| 8 | 8 |
| 9 #include "v8.h" | 9 #include "v8.h" |
| 10 | 10 |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 277 v8::internal::Code* func_code = func->code(); | 277 v8::internal::Code* func_code = func->code(); |
| 278 CHECK(func_code->IsCode()); | 278 CHECK(func_code->IsCode()); |
| 279 func_code->Print(); | 279 func_code->Print(); |
| 280 #endif | 280 #endif |
| 281 | 281 |
| 282 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); | 282 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); |
| 283 CHECK_EQ(*func, *GetGlobalJSFunction(func_name)); | 283 CHECK_EQ(*func, *GetGlobalJSFunction(func_name)); |
| 284 } | 284 } |
| 285 | 285 |
| 286 | 286 |
| 287 // This test verifies that stack tracing works when called during |
| 288 // execution of a native function called from JS code. In this case, |
| 289 // StackTracer uses Top::c_entry_fp as a starting point for stack |
| 290 // walking. |
| 287 TEST(CFromJSStackTrace) { | 291 TEST(CFromJSStackTrace) { |
| 288 TickSample sample; | 292 TickSample sample; |
| 289 InitTraceEnv(&sample); | 293 InitTraceEnv(&sample); |
| 290 | 294 |
| 291 InitializeVM(); | 295 InitializeVM(); |
| 292 v8::HandleScope scope; | 296 v8::HandleScope scope; |
| 297 // Create global function JSFuncDoTrace which calls |
| 298 // extension function trace() with the current frame pointer value. |
| 293 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); | 299 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); |
| 294 Local<Value> result = CompileRun( | 300 Local<Value> result = CompileRun( |
| 295 "function JSTrace() {" | 301 "function JSTrace() {" |
| 296 " JSFuncDoTrace();" | 302 " JSFuncDoTrace();" |
| 297 "};\n" | 303 "};\n" |
| 298 "JSTrace();\n" | 304 "JSTrace();\n" |
| 299 "true;"); | 305 "true;"); |
| 300 CHECK(!result.IsEmpty()); | 306 CHECK(!result.IsEmpty()); |
| 307 // When stack tracer is invoked, the stack should look as follows: |
| 308 // script [JS] |
| 309 // JSTrace() [JS] |
| 310 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] |
| 311 // trace(EBP encoded as Smi) [native (extension)] |
| 312 // DoTrace(EBP) [native] |
| 313 // StackTracer::Trace |
| 301 CHECK_GT(sample.frames_count, 1); | 314 CHECK_GT(sample.frames_count, 1); |
| 302 // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace" | 315 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" |
| 303 CheckRetAddrIsInJSFunction("JSFuncDoTrace", | 316 CheckRetAddrIsInJSFunction("JSFuncDoTrace", |
| 304 sample.stack[0]); | 317 sample.stack[0]); |
| 305 CheckRetAddrIsInJSFunction("JSTrace", | 318 CheckRetAddrIsInJSFunction("JSTrace", |
| 306 sample.stack[1]); | 319 sample.stack[1]); |
| 307 } | 320 } |
| 308 | 321 |
| 309 | 322 |
| 323 // This test verifies that stack tracing works when called during |
| 324 // execution of JS code. However, as calling StackTracer requires |
| 325 // entering native code, we can only emulate pure JS by erasing |
| 326 // Top::c_entry_fp value. In this case, StackTracer uses passed frame |
| 327 // pointer value as a starting point for stack walking. |
| 310 TEST(PureJSStackTrace) { | 328 TEST(PureJSStackTrace) { |
| 311 TickSample sample; | 329 TickSample sample; |
| 312 InitTraceEnv(&sample); | 330 InitTraceEnv(&sample); |
| 313 | 331 |
| 314 InitializeVM(); | 332 InitializeVM(); |
| 315 v8::HandleScope scope; | 333 v8::HandleScope scope; |
| 334 // Create global function JSFuncDoTrace which calls |
| 335 // extension function js_trace() with the current frame pointer value. |
| 316 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); | 336 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); |
| 317 Local<Value> result = CompileRun( | 337 Local<Value> result = CompileRun( |
| 318 "function JSTrace() {" | 338 "function JSTrace() {" |
| 319 " JSFuncDoTrace();" | 339 " JSFuncDoTrace();" |
| 320 "};\n" | 340 "};\n" |
| 321 "function OuterJSTrace() {" | 341 "function OuterJSTrace() {" |
| 322 " JSTrace();" | 342 " JSTrace();" |
| 323 "};\n" | 343 "};\n" |
| 324 "OuterJSTrace();\n" | 344 "OuterJSTrace();\n" |
| 325 "true;"); | 345 "true;"); |
| 326 CHECK(!result.IsEmpty()); | 346 CHECK(!result.IsEmpty()); |
| 327 // The last JS function called. | 347 // When stack tracer is invoked, the stack should look as follows: |
| 348 // script [JS] |
| 349 // OuterJSTrace() [JS] |
| 350 // JSTrace() [JS] |
| 351 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] |
| 352 // js_trace(EBP encoded as Smi) [native (extension)] |
| 353 // DoTraceHideCEntryFPAddress(EBP) [native] |
| 354 // StackTracer::Trace |
| 355 // |
| 356 // The last JS function called. It is only visible through |
| 357 // sample.function, as its return address is above captured EBP value. |
| 328 CHECK_EQ(GetGlobalJSFunction("JSFuncDoTrace")->address(), | 358 CHECK_EQ(GetGlobalJSFunction("JSFuncDoTrace")->address(), |
| 329 sample.function); | 359 sample.function); |
| 330 CHECK_GT(sample.frames_count, 1); | 360 CHECK_GT(sample.frames_count, 1); |
| 331 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" | 361 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" |
| 332 CheckRetAddrIsInJSFunction("JSTrace", | 362 CheckRetAddrIsInJSFunction("JSTrace", |
| 333 sample.stack[0]); | 363 sample.stack[0]); |
| 334 CheckRetAddrIsInJSFunction("OuterJSTrace", | 364 CheckRetAddrIsInJSFunction("OuterJSTrace", |
| 335 sample.stack[1]); | 365 sample.stack[1]); |
| 336 } | 366 } |
| 337 | 367 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 354 static int CFunc(int depth) { | 384 static int CFunc(int depth) { |
| 355 if (depth <= 0) { | 385 if (depth <= 0) { |
| 356 CFuncDoTrace(0); | 386 CFuncDoTrace(0); |
| 357 return 0; | 387 return 0; |
| 358 } else { | 388 } else { |
| 359 return CFunc(depth - 1) + 1; | 389 return CFunc(depth - 1) + 1; |
| 360 } | 390 } |
| 361 } | 391 } |
| 362 | 392 |
| 363 | 393 |
| 394 // This test verifies that stack tracing doesn't crash when called on |
| 395 // pure native code. StackTracer only unrolls JS code, so we can't |
| 396 // get any meaningful info here. |
| 364 TEST(PureCStackTrace) { | 397 TEST(PureCStackTrace) { |
| 365 TickSample sample; | 398 TickSample sample; |
| 366 InitTraceEnv(&sample); | 399 InitTraceEnv(&sample); |
| 367 // Check that sampler doesn't crash | 400 // Check that sampler doesn't crash |
| 368 CHECK_EQ(10, CFunc(10)); | 401 CHECK_EQ(10, CFunc(10)); |
| 369 } | 402 } |
| 370 | 403 |
| 371 | 404 |
| 372 TEST(JsEntrySp) { | 405 TEST(JsEntrySp) { |
| 373 InitializeVM(); | 406 InitializeVM(); |
| 374 v8::HandleScope scope; | 407 v8::HandleScope scope; |
| 375 CHECK_EQ(0, GetJsEntrySp()); | 408 CHECK_EQ(0, GetJsEntrySp()); |
| 376 CompileRun("a = 1; b = a + 1;"); | 409 CompileRun("a = 1; b = a + 1;"); |
| 377 CHECK_EQ(0, GetJsEntrySp()); | 410 CHECK_EQ(0, GetJsEntrySp()); |
| 378 CompileRun("js_entry_sp();"); | 411 CompileRun("js_entry_sp();"); |
| 379 CHECK_EQ(0, GetJsEntrySp()); | 412 CHECK_EQ(0, GetJsEntrySp()); |
| 380 CompileRun("js_entry_sp_level2();"); | 413 CompileRun("js_entry_sp_level2();"); |
| 381 CHECK_EQ(0, GetJsEntrySp()); | 414 CHECK_EQ(0, GetJsEntrySp()); |
| 382 } | 415 } |
| 383 | 416 |
| 384 #endif // ENABLE_LOGGING_AND_PROFILING | 417 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |