Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: test/cctest/test-log-ia32.cc

Issue 108015: Restore stack backtrace tests removed in revision 1785. (Closed)
Patch Set: Addressed Kevin's comments Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/ia32/codegen-ia32.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2009 the V8 project authors. All rights reserved. 1 // Copyright 2006-2009 the V8 project authors. All rights reserved.
2 // 2 //
3 // Tests of profiler-related functions from log.h 3 // Tests of profiler-related functions from log.h
4 4
5 #ifdef ENABLE_LOGGING_AND_PROFILING 5 #ifdef ENABLE_LOGGING_AND_PROFILING
6 6
7 #include <stdlib.h> 7 #include <stdlib.h>
8 8
9 #include "v8.h" 9 #include "v8.h"
10 10
11 #include "codegen.h"
11 #include "log.h" 12 #include "log.h"
12 #include "top.h" 13 #include "top.h"
13 #include "cctest.h" 14 #include "cctest.h"
15 #include "disassembler.h"
14 16
15 using v8::Function; 17 using v8::Function;
16 using v8::Local; 18 using v8::Local;
17 using v8::Object; 19 using v8::Object;
18 using v8::Script; 20 using v8::Script;
19 using v8::String; 21 using v8::String;
20 using v8::Value; 22 using v8::Value;
21 23
22 using v8::internal::byte; 24 using v8::internal::byte;
25 using v8::internal::Address;
23 using v8::internal::Handle; 26 using v8::internal::Handle;
24 using v8::internal::JSFunction; 27 using v8::internal::JSFunction;
25 using v8::internal::StackTracer; 28 using v8::internal::StackTracer;
26 using v8::internal::TickSample; 29 using v8::internal::TickSample;
27 using v8::internal::Top; 30 using v8::internal::Top;
28 31
32 namespace i = v8::internal;
33
29 34
30 static v8::Persistent<v8::Context> env; 35 static v8::Persistent<v8::Context> env;
31 36
32 37
33 static struct { 38 static struct {
34 StackTracer* tracer; 39 StackTracer* tracer;
35 TickSample* sample; 40 TickSample* sample;
36 } trace_env = { NULL, NULL }; 41 } trace_env = { NULL, NULL };
37 42
38 43
39 static void InitTraceEnv(StackTracer* tracer, TickSample* sample) { 44 static void InitTraceEnv(StackTracer* tracer, TickSample* sample) {
40 trace_env.tracer = tracer; 45 trace_env.tracer = tracer;
41 trace_env.sample = sample; 46 trace_env.sample = sample;
42 } 47 }
43 48
44 49
45 static void DoTrace(unsigned int fp) { 50 static void DoTrace(Address fp) {
46 trace_env.sample->fp = fp; 51 trace_env.sample->fp = reinterpret_cast<uintptr_t>(fp);
47 // sp is only used to define stack high bound 52 // sp is only used to define stack high bound
48 trace_env.sample->sp = 53 trace_env.sample->sp =
49 reinterpret_cast<unsigned int>(trace_env.sample) - 10240; 54 reinterpret_cast<unsigned int>(trace_env.sample) - 10240;
50 trace_env.tracer->Trace(trace_env.sample); 55 trace_env.tracer->Trace(trace_env.sample);
51 } 56 }
52 57
53 58
54 // Hide c_entry_fp to emulate situation when sampling is done while 59 // Hide c_entry_fp to emulate situation when sampling is done while
55 // pure JS code is being executed 60 // pure JS code is being executed
56 static void DoTraceHideCEntryFPAddress(unsigned int fp) { 61 static void DoTraceHideCEntryFPAddress(Address fp) {
57 v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); 62 v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address());
58 CHECK(saved_c_frame_fp); 63 CHECK(saved_c_frame_fp);
59 *(Top::c_entry_fp_address()) = 0; 64 *(Top::c_entry_fp_address()) = 0;
60 DoTrace(fp); 65 DoTrace(fp);
61 *(Top::c_entry_fp_address()) = saved_c_frame_fp; 66 *(Top::c_entry_fp_address()) = saved_c_frame_fp;
62 } 67 }
63 68
64 69
70 static void CheckRetAddrIsInFunction(const char* func_name,
71 Address ret_addr,
72 Address func_start_addr,
73 unsigned int func_len) {
74 printf("CheckRetAddrIsInFunction \"%s\": %p %p %p\n",
75 func_name, func_start_addr, ret_addr, func_start_addr + func_len);
76 CHECK_GE(ret_addr, func_start_addr);
77 CHECK_GE(func_start_addr + func_len, ret_addr);
78 }
79
80
81 static void CheckRetAddrIsInJSFunction(const char* func_name,
82 Address ret_addr,
83 Handle<JSFunction> func) {
84 v8::internal::Code* func_code = func->code();
85 CheckRetAddrIsInFunction(
86 func_name, ret_addr,
87 func_code->instruction_start(),
88 func_code->ExecutableSize());
89 }
90
91
65 // --- T r a c e E x t e n s i o n --- 92 // --- T r a c e E x t e n s i o n ---
66 93
67 class TraceExtension : public v8::Extension { 94 class TraceExtension : public v8::Extension {
68 public: 95 public:
69 TraceExtension() : v8::Extension("v8/trace", kSource) { } 96 TraceExtension() : v8::Extension("v8/trace", kSource) { }
70 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( 97 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
71 v8::Handle<String> name); 98 v8::Handle<String> name);
72 static v8::Handle<v8::Value> Trace(const v8::Arguments& args); 99 static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
73 static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args); 100 static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
74 private: 101 private:
75 static unsigned int GetFP(const v8::Arguments& args); 102 static Address GetFP(const v8::Arguments& args);
76 static const char* kSource; 103 static const char* kSource;
77 }; 104 };
78 105
79 106
80 const char* TraceExtension::kSource = 107 const char* TraceExtension::kSource =
81 "native function trace();" 108 "native function trace();"
82 "native function js_trace();"; 109 "native function js_trace();";
83 110
84 111
85 v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction( 112 v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
86 v8::Handle<String> name) { 113 v8::Handle<String> name) {
87 if (name->Equals(String::New("trace"))) { 114 if (name->Equals(String::New("trace"))) {
88 return v8::FunctionTemplate::New(TraceExtension::Trace); 115 return v8::FunctionTemplate::New(TraceExtension::Trace);
89 } else if (name->Equals(String::New("js_trace"))) { 116 } else if (name->Equals(String::New("js_trace"))) {
90 return v8::FunctionTemplate::New(TraceExtension::JSTrace); 117 return v8::FunctionTemplate::New(TraceExtension::JSTrace);
91 } else { 118 } else {
92 CHECK(false); 119 CHECK(false);
93 return v8::Handle<v8::FunctionTemplate>(); 120 return v8::Handle<v8::FunctionTemplate>();
94 } 121 }
95 } 122 }
96 123
97 124
98 unsigned int TraceExtension::GetFP(const v8::Arguments& args) { 125 Address TraceExtension::GetFP(const v8::Arguments& args) {
99 CHECK_EQ(1, args.Length()); 126 CHECK_EQ(1, args.Length());
100 unsigned int fp = args[0]->Int32Value() << 2; 127 Address fp = reinterpret_cast<Address>(args[0]->Int32Value() << 2);
101 printf("Trace: %08x\n", fp); 128 printf("Trace: %p\n", fp);
102 return fp; 129 return fp;
103 } 130 }
104 131
105 132
106 v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) { 133 v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
107 DoTrace(GetFP(args)); 134 DoTrace(GetFP(args));
108 return v8::Undefined(); 135 return v8::Undefined();
109 } 136 }
110 137
111 138
112 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { 139 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
113 DoTraceHideCEntryFPAddress(GetFP(args)); 140 DoTraceHideCEntryFPAddress(GetFP(args));
114 return v8::Undefined(); 141 return v8::Undefined();
115 } 142 }
116 143
117 144
118 static TraceExtension kTraceExtension; 145 static TraceExtension kTraceExtension;
119 v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension); 146 v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
120 147
121 148
149 static void InitializeVM() {
150 if (env.IsEmpty()) {
151 v8::HandleScope scope;
152 const char* extensions[] = { "v8/trace" };
153 v8::ExtensionConfiguration config(1, extensions);
154 env = v8::Context::New(&config);
155 }
156 v8::HandleScope scope;
157 env->Enter();
158 }
159
160
161 static Handle<JSFunction> CompileFunction(const char* source) {
162 return v8::Utils::OpenHandle(*Script::Compile(String::New(source)));
163 }
164
165
166 static void CompileRun(const char* source) {
167 Script::Compile(String::New(source))->Run();
168 }
169
170
171 static Local<Value> GetGlobalProperty(const char* name) {
172 return env->Global()->Get(String::New(name));
173 }
174
175
176 static Handle<JSFunction> GetGlobalJSFunction(const char* name) {
177 Handle<JSFunction> js_func(JSFunction::cast(
178 *(v8::Utils::OpenHandle(
179 *GetGlobalProperty(name)))));
180 return js_func;
181 }
182
183
184 static void CheckRetAddrIsInJSFunction(const char* func_name,
185 Address ret_addr) {
186 CheckRetAddrIsInJSFunction(func_name, ret_addr,
187 GetGlobalJSFunction(func_name));
188 }
189
190
191 static void SetGlobalProperty(const char* name, Local<Value> value) {
192 env->Global()->Set(String::New(name), value);
193 }
194
195
196 static Handle<v8::internal::String> NewString(const char* s) {
197 return i::Factory::NewStringFromAscii(i::CStrVector(s));
198 }
199
200
201 namespace v8 { namespace internal {
202
203 class CodeGeneratorPatcher {
204 public:
205 CodeGeneratorPatcher() {
206 CodeGenerator::InlineRuntimeLUT genGetFramePointer =
207 {&CodeGenerator::GenerateGetFramePointer, "_GetFramePointer"};
208 // _FastCharCodeAt is not used in our tests.
209 bool result = CodeGenerator::PatchInlineRuntimeEntry(
210 NewString("_FastCharCodeAt"),
211 genGetFramePointer, &oldInlineEntry);
212 CHECK(result);
213 }
214
215 ~CodeGeneratorPatcher() {
216 CHECK(CodeGenerator::PatchInlineRuntimeEntry(
217 NewString("_GetFramePointer"),
218 oldInlineEntry, NULL));
219 }
220
221 private:
222 CodeGenerator::InlineRuntimeLUT oldInlineEntry;
223 };
224
225 } } // namespace v8::internal
226
227
228 // Creates a global function named 'func_name' that calls the tracing
229 // function 'trace_func_name' with an actual EBP register value,
230 // shifted right to be presented as Smi.
231 static void CreateTraceCallerFunction(const char* func_name,
232 const char* trace_func_name) {
233 i::EmbeddedVector<char, 256> trace_call_buf;
234 i::OS::SNPrintF(trace_call_buf, "%s(%%_GetFramePointer());", trace_func_name);
235
236 // Compile the script.
237 i::CodeGeneratorPatcher patcher;
238 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
239 i::FLAG_allow_natives_syntax = true;
240 Handle<JSFunction> func = CompileFunction(trace_call_buf.start());
241 CHECK(!func.is_null());
242 i::FLAG_allow_natives_syntax = allow_natives_syntax;
243
244 #ifdef DEBUG
245 v8::internal::Code* func_code = func->code();
246 CHECK(func_code->IsCode());
247 func_code->Print();
248 #endif
249
250 SetGlobalProperty(func_name, v8::ToApi<Value>(func));
251 }
252
253
254 TEST(CFromJSStackTrace) {
255 TickSample sample;
256 StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
257 InitTraceEnv(&tracer, &sample);
258
259 InitializeVM();
260 v8::HandleScope scope;
261 CreateTraceCallerFunction("JSFuncDoTrace", "trace");
262 CompileRun(
263 "function JSTrace() {"
264 " JSFuncDoTrace();"
265 "};\n"
266 "JSTrace();");
267 CHECK_GT(sample.frames_count, 1);
268 // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace"
269 CheckRetAddrIsInJSFunction("JSFuncDoTrace",
270 sample.stack[0]);
271 CheckRetAddrIsInJSFunction("JSTrace",
272 sample.stack[1]);
273 }
274
275
276 TEST(PureJSStackTrace) {
277 TickSample sample;
278 StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
279 InitTraceEnv(&tracer, &sample);
280
281 InitializeVM();
282 v8::HandleScope scope;
283 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace");
284 CompileRun(
285 "function JSTrace() {"
286 " JSFuncDoTrace();"
287 "};\n"
288 "function OuterJSTrace() {"
289 " JSTrace();"
290 "};\n"
291 "OuterJSTrace();");
292 CHECK_GT(sample.frames_count, 1);
293 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
294 CheckRetAddrIsInJSFunction("JSTrace",
295 sample.stack[0]);
296 CheckRetAddrIsInJSFunction("OuterJSTrace",
297 sample.stack[1]);
298 }
299
300
122 static void CFuncDoTrace() { 301 static void CFuncDoTrace() {
123 unsigned int fp; 302 Address fp;
124 #ifdef __GNUC__ 303 #ifdef __GNUC__
125 fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0)); 304 fp = reinterpret_cast<Address>(__builtin_frame_address(0));
126 #elif defined _MSC_VER 305 #elif defined _MSC_VER
127 __asm mov [fp], ebp // NOLINT 306 __asm mov [fp], ebp // NOLINT
128 #endif 307 #endif
129 DoTrace(fp); 308 DoTrace(fp);
130 } 309 }
131 310
132 311
133 static int CFunc(int depth) { 312 static int CFunc(int depth) {
134 if (depth <= 0) { 313 if (depth <= 0) {
135 CFuncDoTrace(); 314 CFuncDoTrace();
136 return 0; 315 return 0;
137 } else { 316 } else {
138 return CFunc(depth - 1) + 1; 317 return CFunc(depth - 1) + 1;
139 } 318 }
140 } 319 }
141 320
142 321
143 TEST(PureCStackTrace) { 322 TEST(PureCStackTrace) {
144 TickSample sample; 323 TickSample sample;
145 StackTracer tracer(reinterpret_cast<unsigned int>(&sample)); 324 StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
146 InitTraceEnv(&tracer, &sample); 325 InitTraceEnv(&tracer, &sample);
147 // Check that sampler doesn't crash 326 // Check that sampler doesn't crash
148 CHECK_EQ(10, CFunc(10)); 327 CHECK_EQ(10, CFunc(10));
149 } 328 }
150 329
151 330
152 #endif // ENABLE_LOGGING_AND_PROFILING 331 #endif // ENABLE_LOGGING_AND_PROFILING
OLDNEW
« no previous file with comments | « src/ia32/codegen-ia32.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698