// Copyright 2006-2009 the V8 project authors. All rights reserved. // // Tests of profiler-related functions from log.h #ifdef ENABLE_LOGGING_AND_PROFILING #include #include "v8.h" #include "log.h" #include "top.h" #include "cctest.h" using v8::Function; using v8::Local; using v8::Object; using v8::Script; using v8::String; using v8::Value; using v8::internal::byte; using v8::internal::Handle; using v8::internal::JSFunction; using v8::internal::StackTracer; using v8::internal::TickSample; using v8::internal::Top; static v8::Persistent env; static struct { StackTracer* tracer; TickSample* sample; } trace_env = { NULL, NULL }; static void InitTraceEnv(StackTracer* tracer, TickSample* sample) { trace_env.tracer = tracer; trace_env.sample = sample; } static void DoTrace(unsigned int fp) { trace_env.sample->fp = fp; // sp is only used to define stack high bound trace_env.sample->sp = reinterpret_cast(trace_env.sample) - 10240; trace_env.tracer->Trace(trace_env.sample); } // Hide c_entry_fp to emulate situation when sampling is done while // pure JS code is being executed static void DoTraceHideCEntryFPAddress(unsigned int fp) { v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); CHECK(saved_c_frame_fp); *(Top::c_entry_fp_address()) = 0; DoTrace(fp); *(Top::c_entry_fp_address()) = saved_c_frame_fp; } // --- T r a c e E x t e n s i o n --- class TraceExtension : public v8::Extension { public: TraceExtension() : v8::Extension("v8/trace", kSource) { } virtual v8::Handle GetNativeFunction( v8::Handle name); static v8::Handle Trace(const v8::Arguments& args); static v8::Handle JSTrace(const v8::Arguments& args); private: static unsigned int GetFP(const v8::Arguments& args); static const char* kSource; }; const char* TraceExtension::kSource = "native function trace();" "native function js_trace();"; v8::Handle TraceExtension::GetNativeFunction( v8::Handle name) { if (name->Equals(String::New("trace"))) { return v8::FunctionTemplate::New(TraceExtension::Trace); } else if (name->Equals(String::New("js_trace"))) { return v8::FunctionTemplate::New(TraceExtension::JSTrace); } else { CHECK(false); return v8::Handle(); } } unsigned int TraceExtension::GetFP(const v8::Arguments& args) { CHECK_EQ(1, args.Length()); unsigned int fp = args[0]->Int32Value() << 2; printf("Trace: %08x\n", fp); return fp; } v8::Handle TraceExtension::Trace(const v8::Arguments& args) { DoTrace(GetFP(args)); return v8::Undefined(); } v8::Handle TraceExtension::JSTrace(const v8::Arguments& args) { DoTraceHideCEntryFPAddress(GetFP(args)); return v8::Undefined(); } static TraceExtension kTraceExtension; v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension); static void CFuncDoTrace() { unsigned int fp; #ifdef __GNUC__ fp = reinterpret_cast(__builtin_frame_address(0)); #elif defined _MSC_VER __asm mov [fp], ebp // NOLINT #endif DoTrace(fp); } static int CFunc(int depth) { if (depth <= 0) { CFuncDoTrace(); return 0; } else { return CFunc(depth - 1) + 1; } } TEST(PureCStackTrace) { TickSample sample; StackTracer tracer(reinterpret_cast(&sample)); InitTraceEnv(&tracer, &sample); // Check that sampler doesn't crash CHECK_EQ(10, CFunc(10)); } #endif // ENABLE_LOGGING_AND_PROFILING