| 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 |
| 11 #include "codegen.h" | 11 #include "codegen.h" |
| 12 #include "log.h" | 12 #include "log.h" |
| 13 #include "top.h" | 13 #include "isolate.h" |
| 14 #include "cctest.h" | 14 #include "cctest.h" |
| 15 #include "disassembler.h" | 15 #include "disassembler.h" |
| 16 #include "register-allocator-inl.h" | 16 #include "register-allocator-inl.h" |
| 17 | 17 |
| 18 using v8::Function; | 18 using v8::Function; |
| 19 using v8::Local; | 19 using v8::Local; |
| 20 using v8::Object; | 20 using v8::Object; |
| 21 using v8::Script; | 21 using v8::Script; |
| 22 using v8::String; | 22 using v8::String; |
| 23 using v8::Value; | 23 using v8::Value; |
| 24 | 24 |
| 25 using v8::internal::byte; | 25 using v8::internal::byte; |
| 26 using v8::internal::Address; | 26 using v8::internal::Address; |
| 27 using v8::internal::Handle; | 27 using v8::internal::Handle; |
| 28 using v8::internal::Isolate; |
| 28 using v8::internal::JSFunction; | 29 using v8::internal::JSFunction; |
| 29 using v8::internal::StackTracer; | 30 using v8::internal::StackTracer; |
| 30 using v8::internal::TickSample; | 31 using v8::internal::TickSample; |
| 31 using v8::internal::Top; | |
| 32 | 32 |
| 33 namespace i = v8::internal; | 33 namespace i = v8::internal; |
| 34 | 34 |
| 35 | 35 |
| 36 static v8::Persistent<v8::Context> env; | 36 static v8::Persistent<v8::Context> env; |
| 37 | 37 |
| 38 | 38 |
| 39 static struct { | 39 static struct { |
| 40 TickSample* sample; | 40 TickSample* sample; |
| 41 } trace_env = { NULL }; | 41 } trace_env = { NULL }; |
| 42 | 42 |
| 43 | 43 |
| 44 static void InitTraceEnv(TickSample* sample) { | 44 static void InitTraceEnv(TickSample* sample) { |
| 45 trace_env.sample = sample; | 45 trace_env.sample = sample; |
| 46 } | 46 } |
| 47 | 47 |
| 48 | 48 |
| 49 static void DoTrace(Address fp) { | 49 static void DoTrace(Address fp) { |
| 50 trace_env.sample->fp = fp; | 50 trace_env.sample->fp = fp; |
| 51 // sp is only used to define stack high bound | 51 // sp is only used to define stack high bound |
| 52 trace_env.sample->sp = | 52 trace_env.sample->sp = |
| 53 reinterpret_cast<Address>(trace_env.sample) - 10240; | 53 reinterpret_cast<Address>(trace_env.sample) - 10240; |
| 54 StackTracer::Trace(trace_env.sample); | 54 StackTracer::Trace(trace_env.sample); |
| 55 } | 55 } |
| 56 | 56 |
| 57 | 57 |
| 58 // Hide c_entry_fp to emulate situation when sampling is done while | 58 // Hide c_entry_fp to emulate situation when sampling is done while |
| 59 // pure JS code is being executed | 59 // pure JS code is being executed |
| 60 static void DoTraceHideCEntryFPAddress(Address fp) { | 60 static void DoTraceHideCEntryFPAddress(Address fp) { |
| 61 v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); | 61 v8::internal::Address saved_c_frame_fp = |
| 62 *(Isolate::Current()->c_entry_fp_address()); |
| 62 CHECK(saved_c_frame_fp); | 63 CHECK(saved_c_frame_fp); |
| 63 *(Top::c_entry_fp_address()) = 0; | 64 *(Isolate::Current()->c_entry_fp_address()) = 0; |
| 64 DoTrace(fp); | 65 DoTrace(fp); |
| 65 *(Top::c_entry_fp_address()) = saved_c_frame_fp; | 66 *(Isolate::Current()->c_entry_fp_address()) = saved_c_frame_fp; |
| 66 } | 67 } |
| 67 | 68 |
| 68 | 69 |
| 69 // --- T r a c e E x t e n s i o n --- | 70 // --- T r a c e E x t e n s i o n --- |
| 70 | 71 |
| 71 class TraceExtension : public v8::Extension { | 72 class TraceExtension : public v8::Extension { |
| 72 public: | 73 public: |
| 73 TraceExtension() : v8::Extension("v8/trace", kSource) { } | 74 TraceExtension() : v8::Extension("v8/trace", kSource) { } |
| 74 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | 75 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
| 75 v8::Handle<String> name); | 76 v8::Handle<String> name); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 | 125 |
| 125 | 126 |
| 126 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { | 127 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { |
| 127 DoTraceHideCEntryFPAddress(GetFP(args)); | 128 DoTraceHideCEntryFPAddress(GetFP(args)); |
| 128 return v8::Undefined(); | 129 return v8::Undefined(); |
| 129 } | 130 } |
| 130 | 131 |
| 131 | 132 |
| 132 static Address GetJsEntrySp() { | 133 static Address GetJsEntrySp() { |
| 133 CHECK_NE(NULL, i::Isolate::Current()->thread_local_top()); | 134 CHECK_NE(NULL, i::Isolate::Current()->thread_local_top()); |
| 134 return Top::js_entry_sp(i::Isolate::Current()->thread_local_top()); | 135 return Isolate::js_entry_sp(i::Isolate::Current()->thread_local_top()); |
| 135 } | 136 } |
| 136 | 137 |
| 137 | 138 |
| 138 v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) { | 139 v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) { |
| 139 CHECK_NE(0, GetJsEntrySp()); | 140 CHECK_NE(0, GetJsEntrySp()); |
| 140 return v8::Undefined(); | 141 return v8::Undefined(); |
| 141 } | 142 } |
| 142 | 143 |
| 143 | 144 |
| 144 v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2( | 145 v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2( |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 func_code->Print(); | 264 func_code->Print(); |
| 264 #endif | 265 #endif |
| 265 | 266 |
| 266 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); | 267 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); |
| 267 CHECK_EQ(*func, *GetGlobalJSFunction(func_name)); | 268 CHECK_EQ(*func, *GetGlobalJSFunction(func_name)); |
| 268 } | 269 } |
| 269 | 270 |
| 270 | 271 |
| 271 // This test verifies that stack tracing works when called during | 272 // This test verifies that stack tracing works when called during |
| 272 // execution of a native function called from JS code. In this case, | 273 // execution of a native function called from JS code. In this case, |
| 273 // StackTracer uses Top::c_entry_fp as a starting point for stack | 274 // StackTracer uses Isolate::c_entry_fp as a starting point for stack |
| 274 // walking. | 275 // walking. |
| 275 TEST(CFromJSStackTrace) { | 276 TEST(CFromJSStackTrace) { |
| 276 // TODO(711) The hack of replacing the inline runtime function | 277 // TODO(711) The hack of replacing the inline runtime function |
| 277 // RandomHeapNumber with GetFrameNumber does not work with the way the full | 278 // RandomHeapNumber with GetFrameNumber does not work with the way the full |
| 278 // compiler generates inline runtime calls. | 279 // compiler generates inline runtime calls. |
| 279 i::FLAG_always_full_compiler = false; | 280 i::FLAG_always_full_compiler = false; |
| 280 | 281 |
| 281 TickSample sample; | 282 TickSample sample; |
| 282 InitTraceEnv(&sample); | 283 InitTraceEnv(&sample); |
| 283 | 284 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 303 CHECK_GT(sample.frames_count, 1); | 304 CHECK_GT(sample.frames_count, 1); |
| 304 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" | 305 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" |
| 305 CheckObjectIsJSFunction("JSFuncDoTrace", sample.stack[0]); | 306 CheckObjectIsJSFunction("JSFuncDoTrace", sample.stack[0]); |
| 306 CheckObjectIsJSFunction("JSTrace", sample.stack[1]); | 307 CheckObjectIsJSFunction("JSTrace", sample.stack[1]); |
| 307 } | 308 } |
| 308 | 309 |
| 309 | 310 |
| 310 // This test verifies that stack tracing works when called during | 311 // This test verifies that stack tracing works when called during |
| 311 // execution of JS code. However, as calling StackTracer requires | 312 // execution of JS code. However, as calling StackTracer requires |
| 312 // entering native code, we can only emulate pure JS by erasing | 313 // entering native code, we can only emulate pure JS by erasing |
| 313 // Top::c_entry_fp value. In this case, StackTracer uses passed frame | 314 // Isolate::c_entry_fp value. In this case, StackTracer uses passed frame |
| 314 // pointer value as a starting point for stack walking. | 315 // pointer value as a starting point for stack walking. |
| 315 TEST(PureJSStackTrace) { | 316 TEST(PureJSStackTrace) { |
| 316 // TODO(711) The hack of replacing the inline runtime function | 317 // TODO(711) The hack of replacing the inline runtime function |
| 317 // RandomHeapNumber with GetFrameNumber does not work with the way the full | 318 // RandomHeapNumber with GetFrameNumber does not work with the way the full |
| 318 // compiler generates inline runtime calls. | 319 // compiler generates inline runtime calls. |
| 319 i::FLAG_always_full_compiler = false; | 320 i::FLAG_always_full_compiler = false; |
| 320 | 321 |
| 321 TickSample sample; | 322 TickSample sample; |
| 322 InitTraceEnv(&sample); | 323 InitTraceEnv(&sample); |
| 323 | 324 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 CHECK_EQ(0, GetJsEntrySp()); | 399 CHECK_EQ(0, GetJsEntrySp()); |
| 399 CompileRun("a = 1; b = a + 1;"); | 400 CompileRun("a = 1; b = a + 1;"); |
| 400 CHECK_EQ(0, GetJsEntrySp()); | 401 CHECK_EQ(0, GetJsEntrySp()); |
| 401 CompileRun("js_entry_sp();"); | 402 CompileRun("js_entry_sp();"); |
| 402 CHECK_EQ(0, GetJsEntrySp()); | 403 CHECK_EQ(0, GetJsEntrySp()); |
| 403 CompileRun("js_entry_sp_level2();"); | 404 CompileRun("js_entry_sp_level2();"); |
| 404 CHECK_EQ(0, GetJsEntrySp()); | 405 CHECK_EQ(0, GetJsEntrySp()); |
| 405 } | 406 } |
| 406 | 407 |
| 407 #endif // ENABLE_LOGGING_AND_PROFILING | 408 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |