Author: [email protected]
Date: Tue Jun 2 02:33:17 2009
New Revision: 2086
Modified:
branches/bleeding_edge/src/ia32/codegen-ia32.cc
branches/bleeding_edge/src/log.cc
branches/bleeding_edge/src/log.h
branches/bleeding_edge/src/top.cc
branches/bleeding_edge/src/top.h
branches/bleeding_edge/test/cctest/test-log-ia32.cc
Log:
Fix determining of JS lower stack bottom used in profiler's JS stack tracer
to work with Chromium.
My assumption that log initialization happens somewhere near the stack's
bottom is true for V8's sample shell but isn't true for Chromium, causing
many otherwise valid stack addresses to be thrown out. The solution
proposed is to save stack pointer value for the outermost JS function in
ThreadLocalTop similar to c_entry_fp.
Implemented only for IA-32. Currently I'm not dealing with profiling on ARM
and x86-64 anyway.
Review URL: http://codereview.chromium.org/112082
Modified: branches/bleeding_edge/src/ia32/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/codegen-ia32.cc (original)
+++ branches/bleeding_edge/src/ia32/codegen-ia32.cc Tue Jun 2 02:33:17 2009
@@ -7159,6 +7159,9 @@
void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
Label invoke, exit;
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ Label not_outermost_js, not_outermost_js_2;
+#endif
// Setup frame.
__ push(ebp);
@@ -7177,6 +7180,15 @@
ExternalReference c_entry_fp(Top::k_c_entry_fp_address);
__ push(Operand::StaticVariable(c_entry_fp));
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ // If this is the outermost JS call, set js_entry_sp value.
+ ExternalReference js_entry_sp(Top::k_js_entry_sp_address);
+ __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0));
+ __ j(NegateCondition(equal), ¬_outermost_js);
+ __ mov(Operand::StaticVariable(js_entry_sp), ebp);
+ __ bind(¬_outermost_js);
+#endif
+
// Call a faked try-block that does the invoke.
__ call(&invoke);
@@ -7219,6 +7231,15 @@
__
pop(Operand::StaticVariable(ExternalReference(Top::k_handler_address)));
// Pop next_sp.
__ add(Operand(esp), Immediate(StackHandlerConstants::kSize -
kPointerSize));
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ // If current EBP value is the same as js_entry_sp value, it means that
+ // the current function is the outermost.
+ __ cmp(ebp, Operand::StaticVariable(js_entry_sp));
+ __ j(NegateCondition(equal), ¬_outermost_js_2);
+ __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0));
+ __ bind(¬_outermost_js_2);
+#endif
// Restore the top frame descriptor from the stack.
__ bind(&exit);
Modified: branches/bleeding_edge/src/log.cc
==============================================================================
--- branches/bleeding_edge/src/log.cc (original)
+++ branches/bleeding_edge/src/log.cc Tue Jun 2 02:33:17 2009
@@ -146,11 +146,18 @@
return;
}
+ const Address js_entry_sp = Top::js_entry_sp(Top::GetCurrentThread());
+ if (js_entry_sp == 0) {
+ // Not executing JS now.
+ sample->frames_count = 0;
+ return;
+ }
+
SafeStackTraceFrameIterator it(
reinterpret_cast<Address>(sample->fp),
reinterpret_cast<Address>(sample->sp),
reinterpret_cast<Address>(sample->sp),
- reinterpret_cast<Address>(low_stack_bound_));
+ js_entry_sp);
int i = 0;
while (!it.done() && i < TickSample::kMaxFramesCount) {
sample->stack[i++] = it.frame()->pc();
@@ -166,14 +173,13 @@
//
class Ticker: public Sampler {
public:
- explicit Ticker(int interval, uintptr_t low_stack_bound):
- Sampler(interval, FLAG_prof), window_(NULL), profiler_(NULL),
- stack_tracer_(low_stack_bound) {}
+ explicit Ticker(int interval):
+ Sampler(interval, FLAG_prof), window_(NULL), profiler_(NULL) {}
~Ticker() { if (IsActive()) Stop(); }
void Tick(TickSample* sample) {
- if (IsProfiling()) stack_tracer_.Trace(sample);
+ if (IsProfiling()) StackTracer::Trace(sample);
if (profiler_) profiler_->Insert(sample);
if (window_) window_->AddState(sample->state);
}
@@ -201,7 +207,6 @@
private:
SlidingStateWindow* window_;
Profiler* profiler_;
- StackTracer stack_tracer_;
};
@@ -1002,11 +1007,7 @@
current_state_ = &bottom_state_;
- // as log is initialized early with V8, we can assume that JS execution
- // frames can never reach this point on stack
- int stack_var;
- ticker_ = new Ticker(
- kSamplingIntervalMs, reinterpret_cast<uintptr_t>(&stack_var));
+ ticker_ = new Ticker(kSamplingIntervalMs);
if (FLAG_sliding_state_window && sliding_state_window_ == NULL) {
sliding_state_window_ = new SlidingStateWindow();
Modified: branches/bleeding_edge/src/log.h
==============================================================================
--- branches/bleeding_edge/src/log.h (original)
+++ branches/bleeding_edge/src/log.h Tue Jun 2 02:33:17 2009
@@ -277,14 +277,9 @@
// Class that extracts stack trace, used for profiling.
-class StackTracer BASE_EMBEDDED {
+class StackTracer : public AllStatic {
public:
- explicit StackTracer(uintptr_t low_stack_bound)
- : low_stack_bound_(low_stack_bound) { }
- void Trace(TickSample* sample);
- private:
-
- uintptr_t low_stack_bound_;
+ static void Trace(TickSample* sample);
};
Modified: branches/bleeding_edge/src/top.cc
==============================================================================
--- branches/bleeding_edge/src/top.cc (original)
+++ branches/bleeding_edge/src/top.cc Tue Jun 2 02:33:17 2009
@@ -45,6 +45,7 @@
Address top_addresses[] = {
#define C(name) reinterpret_cast<Address>(Top::name()),
TOP_ADDRESS_LIST(C)
+ TOP_ADDRESS_LIST_PROF(C)
#undef C
NULL
};
@@ -91,6 +92,9 @@
void Top::InitializeThreadLocal() {
thread_local_.c_entry_fp_ = 0;
thread_local_.handler_ = 0;
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ thread_local_.js_entry_sp_ = 0;
+#endif
thread_local_.stack_is_cooked_ = false;
thread_local_.try_catch_handler_ = NULL;
thread_local_.context_ = NULL;
Modified: branches/bleeding_edge/src/top.h
==============================================================================
--- branches/bleeding_edge/src/top.h (original)
+++ branches/bleeding_edge/src/top.h Tue Jun 2 02:33:17 2009
@@ -65,6 +65,9 @@
// Stack.
Address c_entry_fp_; // the frame pointer of the top c entry frame
Address handler_; // try-blocks are chained through the stack
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ Address js_entry_sp_; // the stack pointer of the bottom js entry frame
+#endif
bool stack_is_cooked_;
inline bool stack_is_cooked() { return stack_is_cooked_; }
inline void set_stack_is_cooked(bool value) { stack_is_cooked_ = value; }
@@ -83,11 +86,20 @@
C(pending_exception_address) \
C(external_caught_exception_address)
+#ifdef ENABLE_LOGGING_AND_PROFILING
+#define TOP_ADDRESS_LIST_PROF(C) \
+ C(js_entry_sp_address)
+#else
+#define TOP_ADDRESS_LIST_PROF(C)
+#endif
+
+
class Top {
public:
enum AddressId {
#define C(name) k_##name,
TOP_ADDRESS_LIST(C)
+ TOP_ADDRESS_LIST_PROF(C)
#undef C
k_top_address_count
};
@@ -178,6 +190,16 @@
return &thread_local_.c_entry_fp_;
}
static inline Address* handler_address() { return
&thread_local_.handler_; }
+
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ // Bottom JS entry (see StackTracer::Trace in log.cc).
+ static Address js_entry_sp(ThreadLocalTop* thread) {
+ return thread->js_entry_sp_;
+ }
+ static inline Address* js_entry_sp_address() {
+ return &thread_local_.js_entry_sp_;
+ }
+#endif
// Generated code scratch locations.
static void* formal_count_address() { return
&thread_local_.formal_count_; }
Modified: branches/bleeding_edge/test/cctest/test-log-ia32.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-log-ia32.cc (original)
+++ branches/bleeding_edge/test/cctest/test-log-ia32.cc Tue Jun 2 02:33:17
2009
@@ -37,13 +37,11 @@
static struct {
- StackTracer* tracer;
TickSample* sample;
-} trace_env = { NULL, NULL };
+} trace_env = { NULL };
-static void InitTraceEnv(StackTracer* tracer, TickSample* sample) {
- trace_env.tracer = tracer;
+static void InitTraceEnv(TickSample* sample) {
trace_env.sample = sample;
}
@@ -53,7 +51,7 @@
// sp is only used to define stack high bound
trace_env.sample->sp =
reinterpret_cast<unsigned int>(trace_env.sample) - 10240;
- trace_env.tracer->Trace(trace_env.sample);
+ StackTracer::Trace(trace_env.sample);
}
@@ -99,6 +97,8 @@
v8::Handle<String> name);
static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
+ static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args);
+ static v8::Handle<v8::Value> JSEntrySPLevel2(const v8::Arguments& args);
private:
static Address GetFP(const v8::Arguments& args);
static const char* kSource;
@@ -107,8 +107,9 @@
const char* TraceExtension::kSource =
"native function trace();"
- "native function js_trace();";
-
+ "native function js_trace();"
+ "native function js_entry_sp();"
+ "native function js_entry_sp_level2();";
v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
v8::Handle<String> name) {
@@ -116,6 +117,10 @@
return v8::FunctionTemplate::New(TraceExtension::Trace);
} else if (name->Equals(String::New("js_trace"))) {
return v8::FunctionTemplate::New(TraceExtension::JSTrace);
+ } else if (name->Equals(String::New("js_entry_sp"))) {
+ return v8::FunctionTemplate::New(TraceExtension::JSEntrySP);
+ } else if (name->Equals(String::New("js_entry_sp_level2"))) {
+ return v8::FunctionTemplate::New(TraceExtension::JSEntrySPLevel2);
} else {
CHECK(false);
return v8::Handle<v8::FunctionTemplate>();
@@ -143,6 +148,34 @@
}
+static Address GetJsEntrySp() {
+ CHECK_NE(NULL, Top::GetCurrentThread());
+ return Top::js_entry_sp(Top::GetCurrentThread());
+}
+
+
+v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args)
{
+ CHECK_NE(0, GetJsEntrySp());
+ return v8::Undefined();
+}
+
+
+static void CompileRun(const char* source) {
+ Script::Compile(String::New(source))->Run();
+}
+
+
+v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2(
+ const v8::Arguments& args) {
+ v8::HandleScope scope;
+ const Address js_entry_sp = GetJsEntrySp();
+ CHECK_NE(0, js_entry_sp);
+ CompileRun("js_entry_sp();");
+ CHECK_EQ(js_entry_sp, GetJsEntrySp());
+ return v8::Undefined();
+}
+
+
static TraceExtension kTraceExtension;
v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
@@ -164,11 +197,6 @@
}
-static void CompileRun(const char* source) {
- Script::Compile(String::New(source))->Run();
-}
-
-
static Local<Value> GetGlobalProperty(const char* name) {
return env->Global()->Get(String::New(name));
}
@@ -255,8 +283,7 @@
TEST(CFromJSStackTrace) {
TickSample sample;
- StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
- InitTraceEnv(&tracer, &sample);
+ InitTraceEnv(&sample);
InitializeVM();
v8::HandleScope scope;
@@ -277,8 +304,7 @@
TEST(PureJSStackTrace) {
TickSample sample;
- StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
- InitTraceEnv(&tracer, &sample);
+ InitTraceEnv(&sample);
InitializeVM();
v8::HandleScope scope;
@@ -323,11 +349,22 @@
TEST(PureCStackTrace) {
TickSample sample;
- StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
- InitTraceEnv(&tracer, &sample);
+ InitTraceEnv(&sample);
// Check that sampler doesn't crash
CHECK_EQ(10, CFunc(10));
}
+
+TEST(JsEntrySp) {
+ InitializeVM();
+ v8::HandleScope scope;
+ CHECK_EQ(0, GetJsEntrySp());
+ CompileRun("a = 1; b = a + 1;");
+ CHECK_EQ(0, GetJsEntrySp());
+ CompileRun("js_entry_sp();");
+ CHECK_EQ(0, GetJsEntrySp());
+ CompileRun("js_entry_sp_level2();");
+ CHECK_EQ(0, GetJsEntrySp());
+}
#endif // ENABLE_LOGGING_AND_PROFILING
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---