| 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 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 = *(Top::c_entry_fp_address()); |
| 62 CHECK(saved_c_frame_fp); | 62 CHECK(saved_c_frame_fp); |
| 63 *(Top::c_entry_fp_address()) = 0; | 63 *(Top::c_entry_fp_address()) = 0; |
| 64 DoTrace(fp); | 64 DoTrace(fp); |
| 65 *(Top::c_entry_fp_address()) = saved_c_frame_fp; | 65 *(Top::c_entry_fp_address()) = saved_c_frame_fp; |
| 66 } | 66 } |
| 67 | 67 |
| 68 | 68 |
| 69 static void CheckRetAddrIsInFunction(const char* func_name, | |
| 70 Address ret_addr, | |
| 71 Address func_start_addr, | |
| 72 unsigned int func_len) { | |
| 73 printf("CheckRetAddrIsInFunction \"%s\": %p %p %p\n", | |
| 74 func_name, func_start_addr, ret_addr, func_start_addr + func_len); | |
| 75 CHECK_GE(ret_addr, func_start_addr); | |
| 76 CHECK_GE(func_start_addr + func_len, ret_addr); | |
| 77 } | |
| 78 | |
| 79 | |
| 80 static void CheckRetAddrIsInJSFunction(const char* func_name, | |
| 81 Address ret_addr, | |
| 82 Handle<JSFunction> func) { | |
| 83 v8::internal::Code* func_code = func->code(); | |
| 84 CheckRetAddrIsInFunction( | |
| 85 func_name, ret_addr, | |
| 86 func_code->instruction_start(), | |
| 87 func_code->ExecutableSize()); | |
| 88 } | |
| 89 | |
| 90 | |
| 91 // --- T r a c e E x t e n s i o n --- | 69 // --- T r a c e E x t e n s i o n --- |
| 92 | 70 |
| 93 class TraceExtension : public v8::Extension { | 71 class TraceExtension : public v8::Extension { |
| 94 public: | 72 public: |
| 95 TraceExtension() : v8::Extension("v8/trace", kSource) { } | 73 TraceExtension() : v8::Extension("v8/trace", kSource) { } |
| 96 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | 74 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
| 97 v8::Handle<String> name); | 75 v8::Handle<String> name); |
| 98 static v8::Handle<v8::Value> Trace(const v8::Arguments& args); | 76 static v8::Handle<v8::Value> Trace(const v8::Arguments& args); |
| 99 static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args); | 77 static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args); |
| 100 static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args); | 78 static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 } | 180 } |
| 203 | 181 |
| 204 | 182 |
| 205 static Handle<JSFunction> GetGlobalJSFunction(const char* name) { | 183 static Handle<JSFunction> GetGlobalJSFunction(const char* name) { |
| 206 Handle<JSFunction> result(JSFunction::cast( | 184 Handle<JSFunction> result(JSFunction::cast( |
| 207 *v8::Utils::OpenHandle(*GetGlobalProperty(name)))); | 185 *v8::Utils::OpenHandle(*GetGlobalProperty(name)))); |
| 208 return result; | 186 return result; |
| 209 } | 187 } |
| 210 | 188 |
| 211 | 189 |
| 212 static void CheckRetAddrIsInJSFunction(const char* func_name, | 190 static void CheckObjectIsJSFunction(const char* func_name, |
| 213 Address ret_addr) { | 191 Address addr) { |
| 214 CheckRetAddrIsInJSFunction(func_name, | 192 i::Object* obj = reinterpret_cast<i::Object*>(addr); |
| 215 ret_addr, | 193 CHECK(obj->IsJSFunction()); |
| 216 GetGlobalJSFunction(func_name)); | 194 CHECK(JSFunction::cast(obj)->shared()->name()->IsString()); |
| 195 i::SmartPointer<char> found_name = |
| 196 i::String::cast( |
| 197 JSFunction::cast( |
| 198 obj)->shared()->name())->ToCString(); |
| 199 CHECK_EQ(func_name, *found_name); |
| 217 } | 200 } |
| 218 | 201 |
| 219 | 202 |
| 220 static void SetGlobalProperty(const char* name, Local<Value> value) { | 203 static void SetGlobalProperty(const char* name, Local<Value> value) { |
| 221 env->Global()->Set(String::New(name), value); | 204 env->Global()->Set(String::New(name), value); |
| 222 } | 205 } |
| 223 | 206 |
| 224 | 207 |
| 225 static Handle<v8::internal::String> NewString(const char* s) { | 208 static Handle<v8::internal::String> NewString(const char* s) { |
| 226 return i::Factory::NewStringFromAscii(i::CStrVector(s)); | 209 return i::Factory::NewStringFromAscii(i::CStrVector(s)); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 265 i::EmbeddedVector<char, 256> trace_call_buf; | 248 i::EmbeddedVector<char, 256> trace_call_buf; |
| 266 i::OS::SNPrintF(trace_call_buf, "%s(%%_GetFramePointer());", trace_func_name); | 249 i::OS::SNPrintF(trace_call_buf, "%s(%%_GetFramePointer());", trace_func_name); |
| 267 | 250 |
| 268 // Compile the script. | 251 // Compile the script. |
| 269 i::CodeGeneratorPatcher patcher; | 252 i::CodeGeneratorPatcher patcher; |
| 270 bool allow_natives_syntax = i::FLAG_allow_natives_syntax; | 253 bool allow_natives_syntax = i::FLAG_allow_natives_syntax; |
| 271 i::FLAG_allow_natives_syntax = true; | 254 i::FLAG_allow_natives_syntax = true; |
| 272 Handle<JSFunction> func = CompileFunction(trace_call_buf.start()); | 255 Handle<JSFunction> func = CompileFunction(trace_call_buf.start()); |
| 273 CHECK(!func.is_null()); | 256 CHECK(!func.is_null()); |
| 274 i::FLAG_allow_natives_syntax = allow_natives_syntax; | 257 i::FLAG_allow_natives_syntax = allow_natives_syntax; |
| 258 func->shared()->set_name(*NewString(func_name)); |
| 275 | 259 |
| 276 #ifdef DEBUG | 260 #ifdef DEBUG |
| 277 v8::internal::Code* func_code = func->code(); | 261 v8::internal::Code* func_code = func->code(); |
| 278 CHECK(func_code->IsCode()); | 262 CHECK(func_code->IsCode()); |
| 279 func_code->Print(); | 263 func_code->Print(); |
| 280 #endif | 264 #endif |
| 281 | 265 |
| 282 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); | 266 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); |
| 283 CHECK_EQ(*func, *GetGlobalJSFunction(func_name)); | 267 CHECK_EQ(*func, *GetGlobalJSFunction(func_name)); |
| 284 } | 268 } |
| 285 | 269 |
| 286 | 270 |
| 287 // This test verifies that stack tracing works when called during | 271 // This test verifies that stack tracing works when called during |
| 288 // execution of a native function called from JS code. In this case, | 272 // 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 | 273 // StackTracer uses Top::c_entry_fp as a starting point for stack |
| 290 // walking. | 274 // walking. |
| 291 TEST(CFromJSStackTrace) { | 275 TEST(CFromJSStackTrace) { |
| 276 #if defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64) |
| 277 // TODO(711) The hack of replacing the inline runtime function |
| 278 // RandomHeapNumber with GetFrameNumber does not work with the way the full |
| 279 // compiler generates inline runtime calls. |
| 280 i::FLAG_force_full_compiler = false; |
| 281 #endif |
| 282 |
| 292 TickSample sample; | 283 TickSample sample; |
| 293 InitTraceEnv(&sample); | 284 InitTraceEnv(&sample); |
| 294 | 285 |
| 295 InitializeVM(); | 286 InitializeVM(); |
| 296 v8::HandleScope scope; | 287 v8::HandleScope scope; |
| 297 // Create global function JSFuncDoTrace which calls | 288 // Create global function JSFuncDoTrace which calls |
| 298 // extension function trace() with the current frame pointer value. | 289 // extension function trace() with the current frame pointer value. |
| 299 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); | 290 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); |
| 300 Local<Value> result = CompileRun( | 291 Local<Value> result = CompileRun( |
| 301 "function JSTrace() {" | 292 "function JSTrace() {" |
| 302 " JSFuncDoTrace();" | 293 " JSFuncDoTrace();" |
| 303 "};\n" | 294 "};\n" |
| 304 "JSTrace();\n" | 295 "JSTrace();\n" |
| 305 "true;"); | 296 "true;"); |
| 306 CHECK(!result.IsEmpty()); | 297 CHECK(!result.IsEmpty()); |
| 307 // When stack tracer is invoked, the stack should look as follows: | 298 // When stack tracer is invoked, the stack should look as follows: |
| 308 // script [JS] | 299 // script [JS] |
| 309 // JSTrace() [JS] | 300 // JSTrace() [JS] |
| 310 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] | 301 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] |
| 311 // trace(EBP encoded as Smi) [native (extension)] | 302 // trace(EBP encoded as Smi) [native (extension)] |
| 312 // DoTrace(EBP) [native] | 303 // DoTrace(EBP) [native] |
| 313 // StackTracer::Trace | 304 // StackTracer::Trace |
| 314 CHECK_GT(sample.frames_count, 1); | 305 CHECK_GT(sample.frames_count, 1); |
| 315 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" | 306 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" |
| 316 CheckRetAddrIsInJSFunction("JSFuncDoTrace", | 307 CheckObjectIsJSFunction("JSFuncDoTrace", sample.stack[0]); |
| 317 sample.stack[0]); | 308 CheckObjectIsJSFunction("JSTrace", sample.stack[1]); |
| 318 CheckRetAddrIsInJSFunction("JSTrace", | |
| 319 sample.stack[1]); | |
| 320 } | 309 } |
| 321 | 310 |
| 322 | 311 |
| 323 // This test verifies that stack tracing works when called during | 312 // This test verifies that stack tracing works when called during |
| 324 // execution of JS code. However, as calling StackTracer requires | 313 // execution of JS code. However, as calling StackTracer requires |
| 325 // entering native code, we can only emulate pure JS by erasing | 314 // entering native code, we can only emulate pure JS by erasing |
| 326 // Top::c_entry_fp value. In this case, StackTracer uses passed frame | 315 // Top::c_entry_fp value. In this case, StackTracer uses passed frame |
| 327 // pointer value as a starting point for stack walking. | 316 // pointer value as a starting point for stack walking. |
| 328 TEST(PureJSStackTrace) { | 317 TEST(PureJSStackTrace) { |
| 318 #if defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64) |
| 319 // TODO(711) The hack of replacing the inline runtime function |
| 320 // RandomHeapNumber with GetFrameNumber does not work with the way the full |
| 321 // compiler generates inline runtime calls. |
| 322 i::FLAG_force_full_compiler = false; |
| 323 #endif |
| 324 |
| 329 TickSample sample; | 325 TickSample sample; |
| 330 InitTraceEnv(&sample); | 326 InitTraceEnv(&sample); |
| 331 | 327 |
| 332 InitializeVM(); | 328 InitializeVM(); |
| 333 v8::HandleScope scope; | 329 v8::HandleScope scope; |
| 334 // Create global function JSFuncDoTrace which calls | 330 // Create global function JSFuncDoTrace which calls |
| 335 // extension function js_trace() with the current frame pointer value. | 331 // extension function js_trace() with the current frame pointer value. |
| 336 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); | 332 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); |
| 337 Local<Value> result = CompileRun( | 333 Local<Value> result = CompileRun( |
| 338 "function JSTrace() {" | 334 "function JSTrace() {" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 352 // js_trace(EBP encoded as Smi) [native (extension)] | 348 // js_trace(EBP encoded as Smi) [native (extension)] |
| 353 // DoTraceHideCEntryFPAddress(EBP) [native] | 349 // DoTraceHideCEntryFPAddress(EBP) [native] |
| 354 // StackTracer::Trace | 350 // StackTracer::Trace |
| 355 // | 351 // |
| 356 // The last JS function called. It is only visible through | 352 // The last JS function called. It is only visible through |
| 357 // sample.function, as its return address is above captured EBP value. | 353 // sample.function, as its return address is above captured EBP value. |
| 358 CHECK_EQ(GetGlobalJSFunction("JSFuncDoTrace")->address(), | 354 CHECK_EQ(GetGlobalJSFunction("JSFuncDoTrace")->address(), |
| 359 sample.function); | 355 sample.function); |
| 360 CHECK_GT(sample.frames_count, 1); | 356 CHECK_GT(sample.frames_count, 1); |
| 361 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" | 357 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" |
| 362 CheckRetAddrIsInJSFunction("JSTrace", | 358 CheckObjectIsJSFunction("JSTrace", sample.stack[0]); |
| 363 sample.stack[0]); | 359 CheckObjectIsJSFunction("OuterJSTrace", sample.stack[1]); |
| 364 CheckRetAddrIsInJSFunction("OuterJSTrace", | |
| 365 sample.stack[1]); | |
| 366 } | 360 } |
| 367 | 361 |
| 368 | 362 |
| 369 static void CFuncDoTrace(byte dummy_parameter) { | 363 static void CFuncDoTrace(byte dummy_parameter) { |
| 370 Address fp; | 364 Address fp; |
| 371 #ifdef __GNUC__ | 365 #ifdef __GNUC__ |
| 372 fp = reinterpret_cast<Address>(__builtin_frame_address(0)); | 366 fp = reinterpret_cast<Address>(__builtin_frame_address(0)); |
| 373 #elif defined _MSC_VER | 367 #elif defined _MSC_VER |
| 374 // Approximate a frame pointer address. We compile without base pointers, | 368 // Approximate a frame pointer address. We compile without base pointers, |
| 375 // so we can't trust ebp/rbp. | 369 // so we can't trust ebp/rbp. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 408 CHECK_EQ(0, GetJsEntrySp()); | 402 CHECK_EQ(0, GetJsEntrySp()); |
| 409 CompileRun("a = 1; b = a + 1;"); | 403 CompileRun("a = 1; b = a + 1;"); |
| 410 CHECK_EQ(0, GetJsEntrySp()); | 404 CHECK_EQ(0, GetJsEntrySp()); |
| 411 CompileRun("js_entry_sp();"); | 405 CompileRun("js_entry_sp();"); |
| 412 CHECK_EQ(0, GetJsEntrySp()); | 406 CHECK_EQ(0, GetJsEntrySp()); |
| 413 CompileRun("js_entry_sp_level2();"); | 407 CompileRun("js_entry_sp_level2();"); |
| 414 CHECK_EQ(0, GetJsEntrySp()); | 408 CHECK_EQ(0, GetJsEntrySp()); |
| 415 } | 409 } |
| 416 | 410 |
| 417 #endif // ENABLE_LOGGING_AND_PROFILING | 411 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |