| 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 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 } | 199 } |
| 200 | 200 |
| 201 | 201 |
| 202 static Handle<JSFunction> CompileFunction(const char* source) { | 202 static Handle<JSFunction> CompileFunction(const char* source) { |
| 203 Handle<JSFunction> result(JSFunction::cast( | 203 Handle<JSFunction> result(JSFunction::cast( |
| 204 *v8::Utils::OpenHandle(*Script::Compile(String::New(source))))); | 204 *v8::Utils::OpenHandle(*Script::Compile(String::New(source))))); |
| 205 return result; | 205 return result; |
| 206 } | 206 } |
| 207 | 207 |
| 208 | 208 |
| 209 static Local<Value> GetGlobalProperty(const char* name) { | 209 static void CheckJSFunctionAtAddress(const char* func_name, Address addr) { |
| 210 return env->Global()->Get(String::New(name)); | 210 i::Object* obj = i::HeapObject::FromAddress(addr); |
| 211 } | |
| 212 | |
| 213 | |
| 214 static Handle<JSFunction> GetGlobalJSFunction(const char* name) { | |
| 215 Handle<JSFunction> result(JSFunction::cast( | |
| 216 *v8::Utils::OpenHandle(*GetGlobalProperty(name)))); | |
| 217 return result; | |
| 218 } | |
| 219 | |
| 220 | |
| 221 static void CheckObjectIsJSFunction(const char* func_name, | |
| 222 Address addr) { | |
| 223 i::Object* obj = reinterpret_cast<i::Object*>(addr); | |
| 224 CHECK(obj->IsJSFunction()); | 211 CHECK(obj->IsJSFunction()); |
| 225 CHECK(JSFunction::cast(obj)->shared()->name()->IsString()); | 212 CHECK(JSFunction::cast(obj)->shared()->name()->IsString()); |
| 226 i::SmartPointer<char> found_name = | 213 i::SmartPointer<char> found_name = |
| 227 i::String::cast( | 214 i::String::cast( |
| 228 JSFunction::cast( | 215 JSFunction::cast( |
| 229 obj)->shared()->name())->ToCString(); | 216 obj)->shared()->name())->ToCString(); |
| 230 CHECK_EQ(func_name, *found_name); | 217 CHECK_EQ(func_name, *found_name); |
| 231 } | 218 } |
| 232 | 219 |
| 233 | 220 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 CHECK(!func.is_null()); | 284 CHECK(!func.is_null()); |
| 298 func->shared()->set_name(*NewString(func_name)); | 285 func->shared()->set_name(*NewString(func_name)); |
| 299 | 286 |
| 300 #ifdef DEBUG | 287 #ifdef DEBUG |
| 301 v8::internal::Code* func_code = func->code(); | 288 v8::internal::Code* func_code = func->code(); |
| 302 CHECK(func_code->IsCode()); | 289 CHECK(func_code->IsCode()); |
| 303 func_code->Print(); | 290 func_code->Print(); |
| 304 #endif | 291 #endif |
| 305 | 292 |
| 306 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); | 293 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); |
| 307 CHECK_EQ(*func, *GetGlobalJSFunction(func_name)); | |
| 308 } | 294 } |
| 309 | 295 |
| 310 | 296 |
| 311 // This test verifies that stack tracing works when called during | 297 // This test verifies that stack tracing works when called during |
| 312 // execution of a native function called from JS code. In this case, | 298 // execution of a native function called from JS code. In this case, |
| 313 // StackTracer uses Top::c_entry_fp as a starting point for stack | 299 // StackTracer uses Top::c_entry_fp as a starting point for stack |
| 314 // walking. | 300 // walking. |
| 315 TEST(CFromJSStackTrace) { | 301 TEST(CFromJSStackTrace) { |
| 316 TickSample sample; | 302 TickSample sample; |
| 317 InitTraceEnv(&sample); | 303 InitTraceEnv(&sample); |
| 318 | 304 |
| 319 InitializeVM(); | 305 InitializeVM(); |
| 320 v8::HandleScope scope; | 306 v8::HandleScope scope; |
| 321 // Create global function JSFuncDoTrace which calls | 307 // Create global function JSFuncDoTrace which calls |
| 322 // extension function trace() with the current frame pointer value. | 308 // extension function trace() with the current frame pointer value. |
| 323 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); | 309 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); |
| 324 Local<Value> result = CompileRun( | 310 Local<Value> result = CompileRun( |
| 325 "function JSTrace() {" | 311 "function JSTrace() {" |
| 326 " JSFuncDoTrace();" | 312 " JSFuncDoTrace();" |
| 327 "};\n" | 313 "};\n" |
| 328 "JSTrace();\n" | 314 "JSTrace();\n" |
| 329 "true;"); | 315 "true;"); |
| 330 CHECK(!result.IsEmpty()); | 316 CHECK(!result.IsEmpty()); |
| 331 // When stack tracer is invoked, the stack should look as follows: | 317 // When stack tracer is invoked, the stack should look as follows: |
| 332 // script [JS] | 318 // script [JS] |
| 333 // JSTrace() [JS] | 319 // JSTrace() [JS] |
| 334 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] | 320 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] |
| 335 // trace(EBP encoded as Smi) [native (extension)] | 321 // trace(EBP) [native (extension)] |
| 336 // DoTrace(EBP) [native] | 322 // DoTrace(EBP) [native] |
| 337 // StackTracer::Trace | 323 // StackTracer::Trace |
| 338 CHECK_GT(sample.frames_count, 1); | 324 CHECK_GT(sample.frames_count, 1); |
| 339 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" | 325 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" |
| 340 CheckObjectIsJSFunction("JSFuncDoTrace", sample.stack[0]); | 326 CheckJSFunctionAtAddress("JSFuncDoTrace", sample.stack[0]); |
| 341 CheckObjectIsJSFunction("JSTrace", sample.stack[1]); | 327 CheckJSFunctionAtAddress("JSTrace", sample.stack[1]); |
| 342 } | 328 } |
| 343 | 329 |
| 344 | 330 |
| 345 // This test verifies that stack tracing works when called during | 331 // This test verifies that stack tracing works when called during |
| 346 // execution of JS code. However, as calling StackTracer requires | 332 // execution of JS code. However, as calling StackTracer requires |
| 347 // entering native code, we can only emulate pure JS by erasing | 333 // entering native code, we can only emulate pure JS by erasing |
| 348 // Top::c_entry_fp value. In this case, StackTracer uses passed frame | 334 // Top::c_entry_fp value. In this case, StackTracer uses passed frame |
| 349 // pointer value as a starting point for stack walking. | 335 // pointer value as a starting point for stack walking. |
| 350 TEST(PureJSStackTrace) { | 336 TEST(PureJSStackTrace) { |
| 351 TickSample sample; | 337 TickSample sample; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 363 "function OuterJSTrace() {" | 349 "function OuterJSTrace() {" |
| 364 " JSTrace();" | 350 " JSTrace();" |
| 365 "};\n" | 351 "};\n" |
| 366 "OuterJSTrace();\n" | 352 "OuterJSTrace();\n" |
| 367 "true;"); | 353 "true;"); |
| 368 CHECK(!result.IsEmpty()); | 354 CHECK(!result.IsEmpty()); |
| 369 // When stack tracer is invoked, the stack should look as follows: | 355 // When stack tracer is invoked, the stack should look as follows: |
| 370 // script [JS] | 356 // script [JS] |
| 371 // OuterJSTrace() [JS] | 357 // OuterJSTrace() [JS] |
| 372 // JSTrace() [JS] | 358 // JSTrace() [JS] |
| 373 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] | 359 // JSFuncDoTrace() [JS] |
| 374 // js_trace(EBP encoded as Smi) [native (extension)] | 360 // js_trace(EBP) [native (extension)] |
| 375 // DoTraceHideCEntryFPAddress(EBP) [native] | 361 // DoTraceHideCEntryFPAddress(EBP) [native] |
| 376 // StackTracer::Trace | 362 // StackTracer::Trace |
| 377 // | 363 // |
| 378 // The last JS function called. It is only visible through | 364 // The last JS function called. It is only visible through |
| 379 // sample.function, as its return address is above captured EBP value. | 365 // sample.function, as its return address is above captured EBP value. |
| 380 CHECK_EQ(GetGlobalJSFunction("JSFuncDoTrace")->address(), | 366 CheckJSFunctionAtAddress("JSFuncDoTrace", sample.function); |
| 381 sample.function); | |
| 382 CHECK_GT(sample.frames_count, 1); | 367 CHECK_GT(sample.frames_count, 1); |
| 383 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" | 368 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" |
| 384 CheckObjectIsJSFunction("JSTrace", sample.stack[0]); | 369 CheckJSFunctionAtAddress("JSTrace", sample.stack[0]); |
| 385 CheckObjectIsJSFunction("OuterJSTrace", sample.stack[1]); | 370 CheckJSFunctionAtAddress("OuterJSTrace", sample.stack[1]); |
| 386 } | 371 } |
| 387 | 372 |
| 388 | 373 |
| 389 static void CFuncDoTrace(byte dummy_parameter) { | 374 static void CFuncDoTrace(byte dummy_parameter) { |
| 390 Address fp; | 375 Address fp; |
| 391 #ifdef __GNUC__ | 376 #ifdef __GNUC__ |
| 392 fp = reinterpret_cast<Address>(__builtin_frame_address(0)); | 377 fp = reinterpret_cast<Address>(__builtin_frame_address(0)); |
| 393 #elif defined _MSC_VER | 378 #elif defined _MSC_VER |
| 394 // Approximate a frame pointer address. We compile without base pointers, | 379 // Approximate a frame pointer address. We compile without base pointers, |
| 395 // so we can't trust ebp/rbp. | 380 // so we can't trust ebp/rbp. |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 CHECK_EQ(0, GetJsEntrySp()); | 413 CHECK_EQ(0, GetJsEntrySp()); |
| 429 CompileRun("a = 1; b = a + 1;"); | 414 CompileRun("a = 1; b = a + 1;"); |
| 430 CHECK_EQ(0, GetJsEntrySp()); | 415 CHECK_EQ(0, GetJsEntrySp()); |
| 431 CompileRun("js_entry_sp();"); | 416 CompileRun("js_entry_sp();"); |
| 432 CHECK_EQ(0, GetJsEntrySp()); | 417 CHECK_EQ(0, GetJsEntrySp()); |
| 433 CompileRun("js_entry_sp_level2();"); | 418 CompileRun("js_entry_sp_level2();"); |
| 434 CHECK_EQ(0, GetJsEntrySp()); | 419 CHECK_EQ(0, GetJsEntrySp()); |
| 435 } | 420 } |
| 436 | 421 |
| 437 #endif // ENABLE_LOGGING_AND_PROFILING | 422 #endif // ENABLE_LOGGING_AND_PROFILING |
| OLD | NEW |