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 15 matching lines...) Expand all Loading... |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 // | 27 // |
28 // Tests of profiler-related functions from log.h | 28 // Tests of profiler-related functions from log.h |
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 "codegen.h" | 37 #include "codegen.h" |
37 #include "log.h" | 38 #include "log.h" |
38 #include "top.h" | 39 #include "top.h" |
39 #include "cctest.h" | 40 #include "cctest.h" |
40 #include "disassembler.h" | 41 #include "disassembler.h" |
41 #include "register-allocator-inl.h" | 42 #include "register-allocator-inl.h" |
42 #include "vm-state-inl.h" | 43 #include "vm-state-inl.h" |
43 | 44 |
44 using v8::Function; | 45 using v8::Function; |
45 using v8::Local; | 46 using v8::Local; |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 v8::HandleScope scope; | 194 v8::HandleScope scope; |
194 const char* extensions[] = { "v8/trace" }; | 195 const char* extensions[] = { "v8/trace" }; |
195 v8::ExtensionConfiguration config(1, extensions); | 196 v8::ExtensionConfiguration config(1, extensions); |
196 env = v8::Context::New(&config); | 197 env = v8::Context::New(&config); |
197 } | 198 } |
198 v8::HandleScope scope; | 199 v8::HandleScope scope; |
199 env->Enter(); | 200 env->Enter(); |
200 } | 201 } |
201 | 202 |
202 | 203 |
203 static void CheckJSFunctionAtAddress(const char* func_name, Address addr) { | 204 static bool IsAddressWithinFuncCode(JSFunction* function, Address addr) { |
204 CHECK(i::Heap::Contains(addr)); | 205 i::Code* code = function->code(); |
205 i::Object* obj = i::HeapObject::FromAddress(addr); | 206 return code->contains(addr); |
206 CHECK(obj->IsJSFunction()); | 207 } |
207 CHECK(JSFunction::cast(obj)->shared()->name()->IsString()); | 208 |
208 i::SmartPointer<char> found_name = | 209 static bool IsAddressWithinFuncCode(const char* func_name, Address addr) { |
209 i::String::cast( | 210 v8::Local<v8::Value> func = env->Global()->Get(v8_str(func_name)); |
210 JSFunction::cast( | 211 CHECK(func->IsFunction()); |
211 obj)->shared()->name())->ToCString(); | 212 JSFunction* js_func = JSFunction::cast(*v8::Utils::OpenHandle(*func)); |
212 CHECK_EQ(func_name, *found_name); | 213 return IsAddressWithinFuncCode(js_func, addr); |
213 } | 214 } |
214 | 215 |
215 | 216 |
216 // This C++ function is called as a constructor, to grab the frame pointer | 217 // This C++ function is called as a constructor, to grab the frame pointer |
217 // from the calling function. When this function runs, the stack contains | 218 // from the calling function. When this function runs, the stack contains |
218 // a C_Entry frame and a Construct frame above the calling function's frame. | 219 // a C_Entry frame and a Construct frame above the calling function's frame. |
219 static v8::Handle<Value> construct_call(const v8::Arguments& args) { | 220 static v8::Handle<Value> construct_call(const v8::Arguments& args) { |
220 i::StackFrameIterator frame_iterator; | 221 i::StackFrameIterator frame_iterator; |
221 CHECK(frame_iterator.frame()->is_exit()); | 222 CHECK(frame_iterator.frame()->is_exit()); |
222 frame_iterator.Advance(); | 223 frame_iterator.Advance(); |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 // StackTracer::Trace | 303 // StackTracer::Trace |
303 | 304 |
304 // The VM state tracking keeps track of external callbacks and puts | 305 // The VM state tracking keeps track of external callbacks and puts |
305 // them at the top of the sample stack. | 306 // them at the top of the sample stack. |
306 int base = 0; | 307 int base = 0; |
307 CHECK(sample.stack[0] == FUNCTION_ADDR(TraceExtension::Trace)); | 308 CHECK(sample.stack[0] == FUNCTION_ADDR(TraceExtension::Trace)); |
308 base++; | 309 base++; |
309 | 310 |
310 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" | 311 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" |
311 CHECK_GT(sample.frames_count, base + 1); | 312 CHECK_GT(sample.frames_count, base + 1); |
312 CheckJSFunctionAtAddress("JSFuncDoTrace", sample.stack[base + 0]); | 313 CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0])); |
313 CheckJSFunctionAtAddress("JSTrace", sample.stack[base + 1]); | 314 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1])); |
314 } | 315 } |
315 | 316 |
316 | 317 |
317 // This test verifies that stack tracing works when called during | 318 // This test verifies that stack tracing works when called during |
318 // execution of JS code. However, as calling StackTracer requires | 319 // execution of JS code. However, as calling StackTracer requires |
319 // entering native code, we can only emulate pure JS by erasing | 320 // entering native code, we can only emulate pure JS by erasing |
320 // Top::c_entry_fp value. In this case, StackTracer uses passed frame | 321 // Top::c_entry_fp value. In this case, StackTracer uses passed frame |
321 // pointer value as a starting point for stack walking. | 322 // pointer value as a starting point for stack walking. |
322 TEST(PureJSStackTrace) { | 323 TEST(PureJSStackTrace) { |
323 // This test does not pass with inlining enabled since inlined functions | 324 // This test does not pass with inlining enabled since inlined functions |
(...skipping 20 matching lines...) Expand all Loading... |
344 CHECK(!result.IsEmpty()); | 345 CHECK(!result.IsEmpty()); |
345 // When stack tracer is invoked, the stack should look as follows: | 346 // When stack tracer is invoked, the stack should look as follows: |
346 // script [JS] | 347 // script [JS] |
347 // OuterJSTrace() [JS] | 348 // OuterJSTrace() [JS] |
348 // JSTrace() [JS] | 349 // JSTrace() [JS] |
349 // JSFuncDoTrace() [JS] | 350 // JSFuncDoTrace() [JS] |
350 // js_trace(EBP) [native (extension)] | 351 // js_trace(EBP) [native (extension)] |
351 // DoTraceHideCEntryFPAddress(EBP) [native] | 352 // DoTraceHideCEntryFPAddress(EBP) [native] |
352 // StackTracer::Trace | 353 // StackTracer::Trace |
353 // | 354 // |
354 // The last JS function called. It is only visible through | |
355 // sample.function, as its return address is above captured EBP value. | |
356 CheckJSFunctionAtAddress("JSFuncDoTrace", sample.function); | |
357 | 355 |
358 // The VM state tracking keeps track of external callbacks and puts | 356 // The VM state tracking keeps track of external callbacks and puts |
359 // them at the top of the sample stack. | 357 // them at the top of the sample stack. |
360 int base = 0; | 358 int base = 0; |
361 CHECK(sample.stack[0] == FUNCTION_ADDR(TraceExtension::JSTrace)); | 359 CHECK(sample.stack[0] == FUNCTION_ADDR(TraceExtension::JSTrace)); |
362 base++; | 360 base++; |
363 | 361 |
364 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" | 362 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" |
365 CHECK_GT(sample.frames_count, base + 1); | 363 CHECK_GT(sample.frames_count, base + 1); |
366 CheckJSFunctionAtAddress("JSTrace", sample.stack[base + 0]); | 364 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 0])); |
367 CheckJSFunctionAtAddress("OuterJSTrace", sample.stack[base + 1]); | 365 CHECK(IsAddressWithinFuncCode("OuterJSTrace", sample.stack[base + 1])); |
368 } | 366 } |
369 | 367 |
370 | 368 |
371 static void CFuncDoTrace(byte dummy_parameter) { | 369 static void CFuncDoTrace(byte dummy_parameter) { |
372 Address fp; | 370 Address fp; |
373 #ifdef __GNUC__ | 371 #ifdef __GNUC__ |
374 fp = reinterpret_cast<Address>(__builtin_frame_address(0)); | 372 fp = reinterpret_cast<Address>(__builtin_frame_address(0)); |
375 #elif defined _MSC_VER | 373 #elif defined _MSC_VER |
376 // Approximate a frame pointer address. We compile without base pointers, | 374 // Approximate a frame pointer address. We compile without base pointers, |
377 // so we can't trust ebp/rbp. | 375 // so we can't trust ebp/rbp. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 CHECK_EQ(0, GetJsEntrySp()); | 408 CHECK_EQ(0, GetJsEntrySp()); |
411 CompileRun("a = 1; b = a + 1;"); | 409 CompileRun("a = 1; b = a + 1;"); |
412 CHECK_EQ(0, GetJsEntrySp()); | 410 CHECK_EQ(0, GetJsEntrySp()); |
413 CompileRun("js_entry_sp();"); | 411 CompileRun("js_entry_sp();"); |
414 CHECK_EQ(0, GetJsEntrySp()); | 412 CHECK_EQ(0, GetJsEntrySp()); |
415 CompileRun("js_entry_sp_level2();"); | 413 CompileRun("js_entry_sp_level2();"); |
416 CHECK_EQ(0, GetJsEntrySp()); | 414 CHECK_EQ(0, GetJsEntrySp()); |
417 } | 415 } |
418 | 416 |
419 #endif // ENABLE_LOGGING_AND_PROFILING | 417 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |