| 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 | 
|---|