blob: 5bfc1d36beef64ef3c34d6229d9b430dac54fa5a [file] [log] [blame]
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001// Copyright 2011 the V8 project authors. All rights reserved.
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
kasperl@chromium.org061ef742009-02-27 12:16:20 +000027//
28// Tests of profiler-related functions from log.h
29
kasperl@chromium.org061ef742009-02-27 12:16:20 +000030#include <stdlib.h>
31
32#include "v8.h"
33
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000034#include "api.h"
ager@chromium.org9085a012009-05-11 19:22:57 +000035#include "codegen.h"
kasperl@chromium.org061ef742009-02-27 12:16:20 +000036#include "log.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000037#include "isolate.h"
kasperl@chromium.org061ef742009-02-27 12:16:20 +000038#include "cctest.h"
ager@chromium.org9085a012009-05-11 19:22:57 +000039#include "disassembler.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000040#include "vm-state-inl.h"
kasperl@chromium.org061ef742009-02-27 12:16:20 +000041
42using v8::Function;
43using v8::Local;
44using v8::Object;
45using v8::Script;
46using v8::String;
47using v8::Value;
48
49using v8::internal::byte;
ager@chromium.org9085a012009-05-11 19:22:57 +000050using v8::internal::Address;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000051using v8::internal::Handle;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000052using v8::internal::Isolate;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000053using v8::internal::JSFunction;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000054using v8::internal::TickSample;
55
56
kasperl@chromium.org061ef742009-02-27 12:16:20 +000057static struct {
kasperl@chromium.org061ef742009-02-27 12:16:20 +000058 TickSample* sample;
ager@chromium.orge2902be2009-06-08 12:21:35 +000059} trace_env = { NULL };
kasperl@chromium.org061ef742009-02-27 12:16:20 +000060
61
ager@chromium.orge2902be2009-06-08 12:21:35 +000062static void InitTraceEnv(TickSample* sample) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +000063 trace_env.sample = sample;
64}
65
66
ager@chromium.org9085a012009-05-11 19:22:57 +000067static void DoTrace(Address fp) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000068 trace_env.sample->fp = fp;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000069 // sp is only used to define stack high bound
70 trace_env.sample->sp =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000071 reinterpret_cast<Address>(trace_env.sample) - 10240;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000072 trace_env.sample->Trace(Isolate::Current());
kasperl@chromium.org061ef742009-02-27 12:16:20 +000073}
74
75
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000076// Hide c_entry_fp to emulate situation when sampling is done while
77// pure JS code is being executed
ager@chromium.org9085a012009-05-11 19:22:57 +000078static void DoTraceHideCEntryFPAddress(Address fp) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000079 v8::internal::Address saved_c_frame_fp =
80 *(Isolate::Current()->c_entry_fp_address());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000081 CHECK(saved_c_frame_fp);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000082 *(Isolate::Current()->c_entry_fp_address()) = 0;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000083 DoTrace(fp);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000084 *(Isolate::Current()->c_entry_fp_address()) = saved_c_frame_fp;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000085}
86
87
kasperl@chromium.org061ef742009-02-27 12:16:20 +000088// --- T r a c e E x t e n s i o n ---
89
90class TraceExtension : public v8::Extension {
91 public:
92 TraceExtension() : v8::Extension("v8/trace", kSource) { }
93 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000094 v8::Handle<String> name);
kasperl@chromium.org061ef742009-02-27 12:16:20 +000095 static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000096 static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
ager@chromium.orge2902be2009-06-08 12:21:35 +000097 static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args);
98 static v8::Handle<v8::Value> JSEntrySPLevel2(const v8::Arguments& args);
kasperl@chromium.org061ef742009-02-27 12:16:20 +000099 private:
ager@chromium.org9085a012009-05-11 19:22:57 +0000100 static Address GetFP(const v8::Arguments& args);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000101 static const char* kSource;
102};
103
104
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000105const char* TraceExtension::kSource =
106 "native function trace();"
ager@chromium.orge2902be2009-06-08 12:21:35 +0000107 "native function js_trace();"
108 "native function js_entry_sp();"
109 "native function js_entry_sp_level2();";
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000110
111v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000112 v8::Handle<String> name) {
113 if (name->Equals(String::New("trace"))) {
114 return v8::FunctionTemplate::New(TraceExtension::Trace);
115 } else if (name->Equals(String::New("js_trace"))) {
116 return v8::FunctionTemplate::New(TraceExtension::JSTrace);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000117 } else if (name->Equals(String::New("js_entry_sp"))) {
118 return v8::FunctionTemplate::New(TraceExtension::JSEntrySP);
119 } else if (name->Equals(String::New("js_entry_sp_level2"))) {
120 return v8::FunctionTemplate::New(TraceExtension::JSEntrySPLevel2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000121 } else {
122 CHECK(false);
123 return v8::Handle<v8::FunctionTemplate>();
124 }
125}
126
127
ager@chromium.org9085a012009-05-11 19:22:57 +0000128Address TraceExtension::GetFP(const v8::Arguments& args) {
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000129 // Convert frame pointer from encoding as smis in the arguments to a pointer.
130 CHECK_EQ(2, args.Length()); // Ignore second argument on 32-bit platform.
131#if defined(V8_HOST_ARCH_32_BIT)
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000132 Address fp = *reinterpret_cast<Address*>(*args[0]);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000133#elif defined(V8_HOST_ARCH_64_BIT)
134 int64_t low_bits = *reinterpret_cast<uint64_t*>(*args[0]) >> 32;
135 int64_t high_bits = *reinterpret_cast<uint64_t*>(*args[1]);
136 Address fp = reinterpret_cast<Address>(high_bits | low_bits);
137#else
138#error Host architecture is neither 32-bit nor 64-bit.
139#endif
ager@chromium.org9085a012009-05-11 19:22:57 +0000140 printf("Trace: %p\n", fp);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 return fp;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000142}
143
144
145v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000146 DoTrace(GetFP(args));
147 return v8::Undefined();
148}
149
150
151v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
152 DoTraceHideCEntryFPAddress(GetFP(args));
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000153 return v8::Undefined();
154}
155
156
ager@chromium.orge2902be2009-06-08 12:21:35 +0000157static Address GetJsEntrySp() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 CHECK_NE(NULL, i::Isolate::Current()->thread_local_top());
159 return Isolate::js_entry_sp(i::Isolate::Current()->thread_local_top());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000160}
161
162
163v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) {
164 CHECK_NE(0, GetJsEntrySp());
165 return v8::Undefined();
166}
167
168
ager@chromium.orge2902be2009-06-08 12:21:35 +0000169v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2(
170 const v8::Arguments& args) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000171 v8::HandleScope scope(args.GetIsolate());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000172 const Address js_entry_sp = GetJsEntrySp();
173 CHECK_NE(0, js_entry_sp);
174 CompileRun("js_entry_sp();");
175 CHECK_EQ(js_entry_sp, GetJsEntrySp());
176 return v8::Undefined();
177}
178
179
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000180static TraceExtension kTraceExtension;
181v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
182
183
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000184static bool IsAddressWithinFuncCode(JSFunction* function, Address addr) {
185 i::Code* code = function->code();
186 return code->contains(addr);
187}
188
189static bool IsAddressWithinFuncCode(const char* func_name, Address addr) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000190 v8::Local<v8::Value> func = CcTest::env()->Global()->Get(v8_str(func_name));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000191 CHECK(func->IsFunction());
192 JSFunction* js_func = JSFunction::cast(*v8::Utils::OpenHandle(*func));
193 return IsAddressWithinFuncCode(js_func, addr);
ager@chromium.org9085a012009-05-11 19:22:57 +0000194}
195
196
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000197// This C++ function is called as a constructor, to grab the frame pointer
198// from the calling function. When this function runs, the stack contains
199// a C_Entry frame and a Construct frame above the calling function's frame.
200static v8::Handle<Value> construct_call(const v8::Arguments& args) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000201 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
202 i::StackFrameIterator frame_iterator(isolate);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000203 CHECK(frame_iterator.frame()->is_exit());
204 frame_iterator.Advance();
205 CHECK(frame_iterator.frame()->is_construct());
206 frame_iterator.Advance();
207 i::StackFrame* calling_frame = frame_iterator.frame();
208 CHECK(calling_frame->is_java_script());
ager@chromium.org9085a012009-05-11 19:22:57 +0000209
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000210#if defined(V8_HOST_ARCH_32_BIT)
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000211 int32_t low_bits = reinterpret_cast<int32_t>(calling_frame->fp());
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000212 args.This()->Set(v8_str("low_bits"), v8_num(low_bits >> 1));
213#elif defined(V8_HOST_ARCH_64_BIT)
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000214 uint64_t fp = reinterpret_cast<uint64_t>(calling_frame->fp());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000215 int32_t low_bits = static_cast<int32_t>(fp & 0xffffffff);
216 int32_t high_bits = static_cast<int32_t>(fp >> 32);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000217 args.This()->Set(v8_str("low_bits"), v8_num(low_bits));
218 args.This()->Set(v8_str("high_bits"), v8_num(high_bits));
219#else
220#error Host architecture is neither 32-bit nor 64-bit.
221#endif
222 return args.This();
223}
ager@chromium.org9085a012009-05-11 19:22:57 +0000224
ager@chromium.org9085a012009-05-11 19:22:57 +0000225
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000226// Use the API to create a JSFunction object that calls the above C++ function.
227void CreateFramePointerGrabberConstructor(const char* constructor_name) {
228 Local<v8::FunctionTemplate> constructor_template =
229 v8::FunctionTemplate::New(construct_call);
230 constructor_template->SetClassName(v8_str("FPGrabber"));
231 Local<Function> fun = constructor_template->GetFunction();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000232 CcTest::env()->Global()->Set(v8_str(constructor_name), fun);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000233}
ager@chromium.org9085a012009-05-11 19:22:57 +0000234
235
236// Creates a global function named 'func_name' that calls the tracing
237// function 'trace_func_name' with an actual EBP register value,
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000238// encoded as one or two Smis.
ager@chromium.org9085a012009-05-11 19:22:57 +0000239static void CreateTraceCallerFunction(const char* func_name,
240 const char* trace_func_name) {
241 i::EmbeddedVector<char, 256> trace_call_buf;
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000242 i::OS::SNPrintF(trace_call_buf,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000243 "function %s() {"
244 " fp = new FPGrabber();"
245 " %s(fp.low_bits, fp.high_bits);"
246 "}",
247 func_name, trace_func_name);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000248
249 // Create the FPGrabber function, which grabs the caller's frame pointer
250 // when called as a constructor.
251 CreateFramePointerGrabberConstructor("FPGrabber");
ager@chromium.org9085a012009-05-11 19:22:57 +0000252
253 // Compile the script.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000254 CompileRun(trace_call_buf.start());
ager@chromium.org9085a012009-05-11 19:22:57 +0000255}
256
257
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000258// This test verifies that stack tracing works when called during
259// execution of a native function called from JS code. In this case,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000260// TickSample::Trace uses Isolate::c_entry_fp as a starting point for stack
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000261// walking.
ager@chromium.org9085a012009-05-11 19:22:57 +0000262TEST(CFromJSStackTrace) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000263 // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test.
264 i::FLAG_use_inlining = false;
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000265
ager@chromium.org9085a012009-05-11 19:22:57 +0000266 TickSample sample;
ager@chromium.orge2902be2009-06-08 12:21:35 +0000267 InitTraceEnv(&sample);
ager@chromium.org9085a012009-05-11 19:22:57 +0000268
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000269 CcTest::InitializeVM(TRACE_EXTENSION);
270 v8::HandleScope scope(CcTest::isolate());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000271 // Create global function JSFuncDoTrace which calls
272 // extension function trace() with the current frame pointer value.
ager@chromium.org9085a012009-05-11 19:22:57 +0000273 CreateTraceCallerFunction("JSFuncDoTrace", "trace");
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000274 Local<Value> result = CompileRun(
ager@chromium.org9085a012009-05-11 19:22:57 +0000275 "function JSTrace() {"
276 " JSFuncDoTrace();"
277 "};\n"
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000278 "JSTrace();\n"
279 "true;");
280 CHECK(!result.IsEmpty());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000281 // When stack tracer is invoked, the stack should look as follows:
282 // script [JS]
283 // JSTrace() [JS]
284 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi]
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000285 // trace(EBP) [native (extension)]
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000286 // DoTrace(EBP) [native]
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000287 // TickSample::Trace
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000288
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000289 CHECK(sample.external_callback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000290 CHECK_EQ(FUNCTION_ADDR(TraceExtension::Trace), sample.external_callback);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000291
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000292 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000293 int base = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000294 CHECK_GT(sample.frames_count, base + 1);
jkummerow@chromium.org531dfe82012-03-20 13:01:16 +0000295
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000296 CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0]));
297 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1]));
ager@chromium.org9085a012009-05-11 19:22:57 +0000298}
299
300
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000301// This test verifies that stack tracing works when called during
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000302// execution of JS code. However, as calling TickSample::Trace requires
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000303// entering native code, we can only emulate pure JS by erasing
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000304// Isolate::c_entry_fp value. In this case, TickSample::Trace uses passed frame
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000305// pointer value as a starting point for stack walking.
ager@chromium.org9085a012009-05-11 19:22:57 +0000306TEST(PureJSStackTrace) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000307 // This test does not pass with inlining enabled since inlined functions
308 // don't appear in the stack trace.
309 i::FLAG_use_inlining = false;
310
ager@chromium.org9085a012009-05-11 19:22:57 +0000311 TickSample sample;
ager@chromium.orge2902be2009-06-08 12:21:35 +0000312 InitTraceEnv(&sample);
ager@chromium.org9085a012009-05-11 19:22:57 +0000313
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000314 CcTest::InitializeVM(TRACE_EXTENSION);
315 v8::HandleScope scope(CcTest::isolate());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000316 // Create global function JSFuncDoTrace which calls
317 // extension function js_trace() with the current frame pointer value.
ager@chromium.org9085a012009-05-11 19:22:57 +0000318 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace");
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000319 Local<Value> result = CompileRun(
ager@chromium.org9085a012009-05-11 19:22:57 +0000320 "function JSTrace() {"
321 " JSFuncDoTrace();"
322 "};\n"
323 "function OuterJSTrace() {"
324 " JSTrace();"
325 "};\n"
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000326 "OuterJSTrace();\n"
327 "true;");
328 CHECK(!result.IsEmpty());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000329 // When stack tracer is invoked, the stack should look as follows:
330 // script [JS]
331 // OuterJSTrace() [JS]
332 // JSTrace() [JS]
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000333 // JSFuncDoTrace() [JS]
334 // js_trace(EBP) [native (extension)]
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000335 // DoTraceHideCEntryFPAddress(EBP) [native]
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000336 // TickSample::Trace
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000337 //
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000338
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000339 CHECK(sample.external_callback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 CHECK_EQ(FUNCTION_ADDR(TraceExtension::JSTrace), sample.external_callback);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000341
ager@chromium.org9085a012009-05-11 19:22:57 +0000342 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000343 int base = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000344 CHECK_GT(sample.frames_count, base + 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000345 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 0]));
346 CHECK(IsAddressWithinFuncCode("OuterJSTrace", sample.stack[base + 1]));
ager@chromium.org9085a012009-05-11 19:22:57 +0000347}
348
349
ager@chromium.org3811b432009-10-28 14:53:37 +0000350static void CFuncDoTrace(byte dummy_parameter) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000351 Address fp;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000352#ifdef __GNUC__
ager@chromium.org9085a012009-05-11 19:22:57 +0000353 fp = reinterpret_cast<Address>(__builtin_frame_address(0));
ager@chromium.org3811b432009-10-28 14:53:37 +0000354#elif defined _MSC_VER
355 // Approximate a frame pointer address. We compile without base pointers,
356 // so we can't trust ebp/rbp.
357 fp = &dummy_parameter - 2 * sizeof(void*); // NOLINT
358#else
359#error Unexpected platform.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000360#endif
361 DoTrace(fp);
362}
363
364
365static int CFunc(int depth) {
366 if (depth <= 0) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000367 CFuncDoTrace(0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000368 return 0;
369 } else {
370 return CFunc(depth - 1) + 1;
371 }
372}
373
374
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000375// This test verifies that stack tracing doesn't crash when called on
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000376// pure native code. TickSample::Trace only unrolls JS code, so we can't
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000377// get any meaningful info here.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000378TEST(PureCStackTrace) {
379 TickSample sample;
ager@chromium.orge2902be2009-06-08 12:21:35 +0000380 InitTraceEnv(&sample);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000381 CcTest::InitializeVM(TRACE_EXTENSION);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000382 // Check that sampler doesn't crash
383 CHECK_EQ(10, CFunc(10));
384}
385
386
ager@chromium.orge2902be2009-06-08 12:21:35 +0000387TEST(JsEntrySp) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000388 CcTest::InitializeVM(TRACE_EXTENSION);
389 v8::HandleScope scope(CcTest::isolate());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000390 CHECK_EQ(0, GetJsEntrySp());
391 CompileRun("a = 1; b = a + 1;");
392 CHECK_EQ(0, GetJsEntrySp());
393 CompileRun("js_entry_sp();");
394 CHECK_EQ(0, GetJsEntrySp());
395 CompileRun("js_entry_sp_level2();");
396 CHECK_EQ(0, GetJsEntrySp());
397}