| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 18 matching lines...) Expand all Loading... |
| 29 | 29 |
| 30 #ifdef ENABLE_LOGGING_AND_PROFILING | 30 #ifdef ENABLE_LOGGING_AND_PROFILING |
| 31 | 31 |
| 32 #include <stdlib.h> | 32 #include <stdlib.h> |
| 33 | 33 |
| 34 #include "v8.h" | 34 #include "v8.h" |
| 35 | 35 |
| 36 #include "api.h" | 36 #include "api.h" |
| 37 #include "codegen.h" | 37 #include "codegen.h" |
| 38 #include "log.h" | 38 #include "log.h" |
| 39 #include "top.h" | 39 #include "isolate.h" |
| 40 #include "cctest.h" | 40 #include "cctest.h" |
| 41 #include "disassembler.h" | 41 #include "disassembler.h" |
| 42 #include "register-allocator-inl.h" | 42 #include "register-allocator-inl.h" |
| 43 #include "vm-state-inl.h" | 43 #include "vm-state-inl.h" |
| 44 | 44 |
| 45 using v8::Function; | 45 using v8::Function; |
| 46 using v8::Local; | 46 using v8::Local; |
| 47 using v8::Object; | 47 using v8::Object; |
| 48 using v8::Script; | 48 using v8::Script; |
| 49 using v8::String; | 49 using v8::String; |
| 50 using v8::Value; | 50 using v8::Value; |
| 51 | 51 |
| 52 using v8::internal::byte; | 52 using v8::internal::byte; |
| 53 using v8::internal::Address; | 53 using v8::internal::Address; |
| 54 using v8::internal::Handle; | 54 using v8::internal::Handle; |
| 55 using v8::internal::Isolate; |
| 55 using v8::internal::JSFunction; | 56 using v8::internal::JSFunction; |
| 56 using v8::internal::StackTracer; | 57 using v8::internal::StackTracer; |
| 57 using v8::internal::TickSample; | 58 using v8::internal::TickSample; |
| 58 using v8::internal::Top; | |
| 59 | 59 |
| 60 namespace i = v8::internal; | 60 namespace i = v8::internal; |
| 61 | 61 |
| 62 | 62 |
| 63 static v8::Persistent<v8::Context> env; | 63 static v8::Persistent<v8::Context> env; |
| 64 | 64 |
| 65 | 65 |
| 66 static struct { | 66 static struct { |
| 67 TickSample* sample; | 67 TickSample* sample; |
| 68 } trace_env = { NULL }; | 68 } trace_env = { NULL }; |
| 69 | 69 |
| 70 | 70 |
| 71 static void InitTraceEnv(TickSample* sample) { | 71 static void InitTraceEnv(TickSample* sample) { |
| 72 trace_env.sample = sample; | 72 trace_env.sample = sample; |
| 73 } | 73 } |
| 74 | 74 |
| 75 | 75 |
| 76 static void DoTrace(Address fp) { | 76 static void DoTrace(Address fp) { |
| 77 trace_env.sample->fp = fp; | 77 trace_env.sample->fp = fp; |
| 78 // sp is only used to define stack high bound | 78 // sp is only used to define stack high bound |
| 79 trace_env.sample->sp = | 79 trace_env.sample->sp = |
| 80 reinterpret_cast<Address>(trace_env.sample) - 10240; | 80 reinterpret_cast<Address>(trace_env.sample) - 10240; |
| 81 StackTracer::Trace(trace_env.sample); | 81 StackTracer::Trace(Isolate::Current(), trace_env.sample); |
| 82 } | 82 } |
| 83 | 83 |
| 84 | 84 |
| 85 // Hide c_entry_fp to emulate situation when sampling is done while | 85 // Hide c_entry_fp to emulate situation when sampling is done while |
| 86 // pure JS code is being executed | 86 // pure JS code is being executed |
| 87 static void DoTraceHideCEntryFPAddress(Address fp) { | 87 static void DoTraceHideCEntryFPAddress(Address fp) { |
| 88 v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); | 88 v8::internal::Address saved_c_frame_fp = |
| 89 *(Isolate::Current()->c_entry_fp_address()); |
| 89 CHECK(saved_c_frame_fp); | 90 CHECK(saved_c_frame_fp); |
| 90 *(Top::c_entry_fp_address()) = 0; | 91 *(Isolate::Current()->c_entry_fp_address()) = 0; |
| 91 DoTrace(fp); | 92 DoTrace(fp); |
| 92 *(Top::c_entry_fp_address()) = saved_c_frame_fp; | 93 *(Isolate::Current()->c_entry_fp_address()) = saved_c_frame_fp; |
| 93 } | 94 } |
| 94 | 95 |
| 95 | 96 |
| 96 // --- T r a c e E x t e n s i o n --- | 97 // --- T r a c e E x t e n s i o n --- |
| 97 | 98 |
| 98 class TraceExtension : public v8::Extension { | 99 class TraceExtension : public v8::Extension { |
| 99 public: | 100 public: |
| 100 TraceExtension() : v8::Extension("v8/trace", kSource) { } | 101 TraceExtension() : v8::Extension("v8/trace", kSource) { } |
| 101 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | 102 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
| 102 v8::Handle<String> name); | 103 v8::Handle<String> name); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 } | 157 } |
| 157 | 158 |
| 158 | 159 |
| 159 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { | 160 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { |
| 160 DoTraceHideCEntryFPAddress(GetFP(args)); | 161 DoTraceHideCEntryFPAddress(GetFP(args)); |
| 161 return v8::Undefined(); | 162 return v8::Undefined(); |
| 162 } | 163 } |
| 163 | 164 |
| 164 | 165 |
| 165 static Address GetJsEntrySp() { | 166 static Address GetJsEntrySp() { |
| 166 CHECK_NE(NULL, Top::GetCurrentThread()); | 167 CHECK_NE(NULL, i::Isolate::Current()->thread_local_top()); |
| 167 return Top::js_entry_sp(Top::GetCurrentThread()); | 168 return Isolate::js_entry_sp(i::Isolate::Current()->thread_local_top()); |
| 168 } | 169 } |
| 169 | 170 |
| 170 | 171 |
| 171 v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) { | 172 v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) { |
| 172 CHECK_NE(0, GetJsEntrySp()); | 173 CHECK_NE(0, GetJsEntrySp()); |
| 173 return v8::Undefined(); | 174 return v8::Undefined(); |
| 174 } | 175 } |
| 175 | 176 |
| 176 | 177 |
| 177 v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2( | 178 v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2( |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 // when called as a constructor. | 270 // when called as a constructor. |
| 270 CreateFramePointerGrabberConstructor("FPGrabber"); | 271 CreateFramePointerGrabberConstructor("FPGrabber"); |
| 271 | 272 |
| 272 // Compile the script. | 273 // Compile the script. |
| 273 CompileRun(trace_call_buf.start()); | 274 CompileRun(trace_call_buf.start()); |
| 274 } | 275 } |
| 275 | 276 |
| 276 | 277 |
| 277 // This test verifies that stack tracing works when called during | 278 // This test verifies that stack tracing works when called during |
| 278 // execution of a native function called from JS code. In this case, | 279 // execution of a native function called from JS code. In this case, |
| 279 // StackTracer uses Top::c_entry_fp as a starting point for stack | 280 // StackTracer uses Isolate::c_entry_fp as a starting point for stack |
| 280 // walking. | 281 // walking. |
| 281 TEST(CFromJSStackTrace) { | 282 TEST(CFromJSStackTrace) { |
| 282 TickSample sample; | 283 TickSample sample; |
| 283 InitTraceEnv(&sample); | 284 InitTraceEnv(&sample); |
| 284 | 285 |
| 285 InitializeVM(); | 286 InitializeVM(); |
| 286 v8::HandleScope scope; | 287 v8::HandleScope scope; |
| 287 // Create global function JSFuncDoTrace which calls | 288 // Create global function JSFuncDoTrace which calls |
| 288 // extension function trace() with the current frame pointer value. | 289 // extension function trace() with the current frame pointer value. |
| 289 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); | 290 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 311 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" | 312 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" |
| 312 CHECK_GT(sample.frames_count, base + 1); | 313 CHECK_GT(sample.frames_count, base + 1); |
| 313 CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0])); | 314 CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0])); |
| 314 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1])); | 315 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1])); |
| 315 } | 316 } |
| 316 | 317 |
| 317 | 318 |
| 318 // This test verifies that stack tracing works when called during | 319 // This test verifies that stack tracing works when called during |
| 319 // execution of JS code. However, as calling StackTracer requires | 320 // execution of JS code. However, as calling StackTracer requires |
| 320 // entering native code, we can only emulate pure JS by erasing | 321 // entering native code, we can only emulate pure JS by erasing |
| 321 // Top::c_entry_fp value. In this case, StackTracer uses passed frame | 322 // Isolate::c_entry_fp value. In this case, StackTracer uses passed frame |
| 322 // pointer value as a starting point for stack walking. | 323 // pointer value as a starting point for stack walking. |
| 323 TEST(PureJSStackTrace) { | 324 TEST(PureJSStackTrace) { |
| 324 // This test does not pass with inlining enabled since inlined functions | 325 // This test does not pass with inlining enabled since inlined functions |
| 325 // don't appear in the stack trace. | 326 // don't appear in the stack trace. |
| 326 i::FLAG_use_inlining = false; | 327 i::FLAG_use_inlining = false; |
| 327 | 328 |
| 328 TickSample sample; | 329 TickSample sample; |
| 329 InitTraceEnv(&sample); | 330 InitTraceEnv(&sample); |
| 330 | 331 |
| 331 InitializeVM(); | 332 InitializeVM(); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 } | 391 } |
| 391 } | 392 } |
| 392 | 393 |
| 393 | 394 |
| 394 // This test verifies that stack tracing doesn't crash when called on | 395 // 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 // pure native code. StackTracer only unrolls JS code, so we can't |
| 396 // get any meaningful info here. | 397 // get any meaningful info here. |
| 397 TEST(PureCStackTrace) { | 398 TEST(PureCStackTrace) { |
| 398 TickSample sample; | 399 TickSample sample; |
| 399 InitTraceEnv(&sample); | 400 InitTraceEnv(&sample); |
| 401 InitializeVM(); |
| 400 // Check that sampler doesn't crash | 402 // Check that sampler doesn't crash |
| 401 CHECK_EQ(10, CFunc(10)); | 403 CHECK_EQ(10, CFunc(10)); |
| 402 } | 404 } |
| 403 | 405 |
| 404 | 406 |
| 405 TEST(JsEntrySp) { | 407 TEST(JsEntrySp) { |
| 406 InitializeVM(); | 408 InitializeVM(); |
| 407 v8::HandleScope scope; | 409 v8::HandleScope scope; |
| 408 CHECK_EQ(0, GetJsEntrySp()); | 410 CHECK_EQ(0, GetJsEntrySp()); |
| 409 CompileRun("a = 1; b = a + 1;"); | 411 CompileRun("a = 1; b = a + 1;"); |
| 410 CHECK_EQ(0, GetJsEntrySp()); | 412 CHECK_EQ(0, GetJsEntrySp()); |
| 411 CompileRun("js_entry_sp();"); | 413 CompileRun("js_entry_sp();"); |
| 412 CHECK_EQ(0, GetJsEntrySp()); | 414 CHECK_EQ(0, GetJsEntrySp()); |
| 413 CompileRun("js_entry_sp_level2();"); | 415 CompileRun("js_entry_sp_level2();"); |
| 414 CHECK_EQ(0, GetJsEntrySp()); | 416 CHECK_EQ(0, GetJsEntrySp()); |
| 415 } | 417 } |
| 416 | 418 |
| 417 #endif // ENABLE_LOGGING_AND_PROFILING | 419 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |