OLD | NEW |
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 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
55 // pure JS code is being executed | 55 // pure JS code is being executed |
56 static void DoTraceHideCEntryFPAddress(unsigned int fp) { | 56 static void DoTraceHideCEntryFPAddress(unsigned int fp) { |
57 v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); | 57 v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); |
58 CHECK(saved_c_frame_fp); | 58 CHECK(saved_c_frame_fp); |
59 *(Top::c_entry_fp_address()) = 0; | 59 *(Top::c_entry_fp_address()) = 0; |
60 DoTrace(fp); | 60 DoTrace(fp); |
61 *(Top::c_entry_fp_address()) = saved_c_frame_fp; | 61 *(Top::c_entry_fp_address()) = saved_c_frame_fp; |
62 } | 62 } |
63 | 63 |
64 | 64 |
65 static void CheckRetAddrIsInFunction(const char* func_name, | |
66 unsigned int ret_addr, | |
67 unsigned int func_start_addr, | |
68 unsigned int func_len) { | |
69 printf("CheckRetAddrIsInFunction \"%s\": %08x %08x %08x\n", | |
70 func_name, func_start_addr, ret_addr, func_start_addr + func_len); | |
71 CHECK_GE(ret_addr, func_start_addr); | |
72 CHECK_GE(func_start_addr + func_len, ret_addr); | |
73 } | |
74 | |
75 | |
76 static void CheckRetAddrIsInJSFunction(const char* func_name, | |
77 unsigned int ret_addr, | |
78 Handle<JSFunction> func) { | |
79 v8::internal::Code* func_code = func->code(); | |
80 CheckRetAddrIsInFunction( | |
81 func_name, ret_addr, | |
82 reinterpret_cast<unsigned int>(func_code->instruction_start()), | |
83 func_code->ExecutableSize()); | |
84 } | |
85 | |
86 | |
87 // --- T r a c e E x t e n s i o n --- | 65 // --- T r a c e E x t e n s i o n --- |
88 | 66 |
89 class TraceExtension : public v8::Extension { | 67 class TraceExtension : public v8::Extension { |
90 public: | 68 public: |
91 TraceExtension() : v8::Extension("v8/trace", kSource) { } | 69 TraceExtension() : v8::Extension("v8/trace", kSource) { } |
92 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | 70 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
93 v8::Handle<String> name); | 71 v8::Handle<String> name); |
94 static v8::Handle<v8::Value> Trace(const v8::Arguments& args); | 72 static v8::Handle<v8::Value> Trace(const v8::Arguments& args); |
95 static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args); | 73 static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args); |
96 private: | 74 private: |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
134 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { | 112 v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { |
135 DoTraceHideCEntryFPAddress(GetFP(args)); | 113 DoTraceHideCEntryFPAddress(GetFP(args)); |
136 return v8::Undefined(); | 114 return v8::Undefined(); |
137 } | 115 } |
138 | 116 |
139 | 117 |
140 static TraceExtension kTraceExtension; | 118 static TraceExtension kTraceExtension; |
141 v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension); | 119 v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension); |
142 | 120 |
143 | 121 |
144 static void InitializeVM() { | |
145 if (env.IsEmpty()) { | |
146 v8::HandleScope scope; | |
147 const char* extensions[] = { "v8/trace" }; | |
148 v8::ExtensionConfiguration config(1, extensions); | |
149 env = v8::Context::New(&config); | |
150 } | |
151 v8::HandleScope scope; | |
152 env->Enter(); | |
153 } | |
154 | |
155 | |
156 static Handle<JSFunction> CompileFunction(const char* source) { | |
157 return v8::Utils::OpenHandle(*Script::Compile(String::New(source))); | |
158 } | |
159 | |
160 | |
161 static void CompileRun(const char* source) { | |
162 Script::Compile(String::New(source))->Run(); | |
163 } | |
164 | |
165 | |
166 static Local<Value> GetGlobalProperty(const char* name) { | |
167 return env->Global()->Get(String::New(name)); | |
168 } | |
169 | |
170 | |
171 static Handle<JSFunction> GetGlobalJSFunction(const char* name) { | |
172 Handle<JSFunction> js_func(JSFunction::cast( | |
173 *(v8::Utils::OpenHandle( | |
174 *GetGlobalProperty(name))))); | |
175 return js_func; | |
176 } | |
177 | |
178 | |
179 static void CheckRetAddrIsInJSFunction(const char* func_name, | |
180 unsigned int ret_addr) { | |
181 CheckRetAddrIsInJSFunction(func_name, ret_addr, | |
182 GetGlobalJSFunction(func_name)); | |
183 } | |
184 | |
185 | |
186 static void SetGlobalProperty(const char* name, Local<Value> value) { | |
187 env->Global()->Set(String::New(name), value); | |
188 } | |
189 | |
190 | |
191 static bool Patch(byte* from, | |
192 size_t num, | |
193 byte* original, | |
194 byte* patch, | |
195 size_t patch_len) { | |
196 byte* to = from + num; | |
197 do { | |
198 from = static_cast<byte*>(memchr(from, *original, to - from)); | |
199 CHECK(from != NULL); | |
200 if (memcmp(original, from, patch_len) == 0) { | |
201 memcpy(from, patch, patch_len); | |
202 return true; | |
203 } else { | |
204 from++; | |
205 } | |
206 } while (to - from > 0); | |
207 return false; | |
208 } | |
209 | |
210 | |
211 // Creates a global function named 'func_name' that calls the tracing | |
212 // function 'trace_func_name' with an actual EBP register value, | |
213 // shifted right to be presented as Smi. | |
214 static void CreateTraceCallerFunction(const char* func_name, | |
215 const char* trace_func_name) { | |
216 ::v8::internal::EmbeddedVector<char, 256> trace_call_buf; | |
217 ::v8::internal::OS::SNPrintF(trace_call_buf, "%s(0x6666);", trace_func_name); | |
218 Handle<JSFunction> func = CompileFunction(trace_call_buf.start()); | |
219 CHECK(!func.is_null()); | |
220 v8::internal::Code* func_code = func->code(); | |
221 CHECK(func_code->IsCode()); | |
222 | |
223 // push 0xcccc (= 0x6666 << 1) | |
224 byte original[] = { 0x68, 0xcc, 0xcc, 0x00, 0x00 }; | |
225 // mov eax,ebp; shr eax; push eax; | |
226 byte patch[] = { 0x89, 0xe8, 0xd1, 0xe8, 0x50 }; | |
227 // Patch generated code to replace pushing of a constant with | |
228 // pushing of ebp contents in a Smi | |
229 CHECK(Patch(func_code->instruction_start(), | |
230 func_code->instruction_size(), | |
231 original, patch, sizeof(patch))); | |
232 | |
233 SetGlobalProperty(func_name, v8::ToApi<Value>(func)); | |
234 } | |
235 | |
236 | |
237 TEST(CFromJSStackTrace) { | |
238 TickSample sample; | |
239 StackTracer tracer(reinterpret_cast<unsigned int>(&sample)); | |
240 InitTraceEnv(&tracer, &sample); | |
241 | |
242 InitializeVM(); | |
243 v8::HandleScope scope; | |
244 CreateTraceCallerFunction("JSFuncDoTrace", "trace"); | |
245 CompileRun( | |
246 "function JSTrace() {" | |
247 " JSFuncDoTrace();" | |
248 "};\n" | |
249 "JSTrace();"); | |
250 CHECK_GT(sample.frames_count, 1); | |
251 // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace" | |
252 CheckRetAddrIsInJSFunction("JSFuncDoTrace", | |
253 reinterpret_cast<unsigned int>(sample.stack[0])); | |
254 CheckRetAddrIsInJSFunction("JSTrace", | |
255 reinterpret_cast<unsigned int>(sample.stack[1])); | |
256 } | |
257 | |
258 | |
259 TEST(PureJSStackTrace) { | |
260 TickSample sample; | |
261 StackTracer tracer(reinterpret_cast<unsigned int>(&sample)); | |
262 InitTraceEnv(&tracer, &sample); | |
263 | |
264 InitializeVM(); | |
265 v8::HandleScope scope; | |
266 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); | |
267 CompileRun( | |
268 "function JSTrace() {" | |
269 " JSFuncDoTrace();" | |
270 "};\n" | |
271 "function OuterJSTrace() {" | |
272 " JSTrace();" | |
273 "};\n" | |
274 "OuterJSTrace();"); | |
275 CHECK_GT(sample.frames_count, 1); | |
276 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" | |
277 CheckRetAddrIsInJSFunction("JSTrace", | |
278 reinterpret_cast<unsigned int>(sample.stack[0])); | |
279 CheckRetAddrIsInJSFunction("OuterJSTrace", | |
280 reinterpret_cast<unsigned int>(sample.stack[1])); | |
281 } | |
282 | |
283 | |
284 static void CFuncDoTrace() { | 122 static void CFuncDoTrace() { |
285 unsigned int fp; | 123 unsigned int fp; |
286 #ifdef __GNUC__ | 124 #ifdef __GNUC__ |
287 fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0)); | 125 fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0)); |
288 #elif defined _MSC_VER | 126 #elif defined _MSC_VER |
289 __asm mov [fp], ebp // NOLINT | 127 __asm mov [fp], ebp // NOLINT |
290 #endif | 128 #endif |
291 DoTrace(fp); | 129 DoTrace(fp); |
292 } | 130 } |
293 | 131 |
(...skipping 11 matching lines...) Expand all Loading... |
305 TEST(PureCStackTrace) { | 143 TEST(PureCStackTrace) { |
306 TickSample sample; | 144 TickSample sample; |
307 StackTracer tracer(reinterpret_cast<unsigned int>(&sample)); | 145 StackTracer tracer(reinterpret_cast<unsigned int>(&sample)); |
308 InitTraceEnv(&tracer, &sample); | 146 InitTraceEnv(&tracer, &sample); |
309 // Check that sampler doesn't crash | 147 // Check that sampler doesn't crash |
310 CHECK_EQ(10, CFunc(10)); | 148 CHECK_EQ(10, CFunc(10)); |
311 } | 149 } |
312 | 150 |
313 | 151 |
314 #endif // ENABLE_LOGGING_AND_PROFILING | 152 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |