v8/test/cctest/test-log-ia32.cc
kmillikin@chromium.org cc0c8d178f Materializing a frame element on the stack by pushing it can cause the
stack pointer to change by more than one in a corner case.  If we push
a constant smi larger than 16 bits, we push it via a temporary
register.  Allocating the temporary can cause a register to be spilled
from the frame somewhere above the stack pointer.

As a fix, do not use pushes to materialize ranges of elements of size
larger than one.

Review URL: http://codereview.chromium.org/92121

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1785 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
2009-04-24 11:26:49 +00:00

153 lines
3.5 KiB
C++

// Copyright 2006-2009 the V8 project authors. All rights reserved.
//
// Tests of profiler-related functions from log.h
#ifdef ENABLE_LOGGING_AND_PROFILING
#include <stdlib.h>
#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<v8::Context> 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<unsigned int>(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<v8::FunctionTemplate> GetNativeFunction(
v8::Handle<String> name);
static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
static v8::Handle<v8::Value> 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<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
v8::Handle<String> 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<v8::FunctionTemplate>();
}
}
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<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
DoTrace(GetFP(args));
return v8::Undefined();
}
v8::Handle<v8::Value> 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<unsigned int>(__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<unsigned int>(&sample));
InitTraceEnv(&tracer, &sample);
// Check that sampler doesn't crash
CHECK_EQ(10, CFunc(10));
}
#endif // ENABLE_LOGGING_AND_PROFILING