blob: 3c34ede8bf406b3c0df498b8a2bbca2e388a54e5 [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
ulan@chromium.org57ff8812013-05-10 08:16:55 +000032// TODO(dcarney): remove
33#define V8_ALLOW_ACCESS_TO_PERSISTENT_IMPLICIT
34#define V8_ALLOW_ACCESS_TO_PERSISTENT_ARROW
35
kasperl@chromium.org061ef742009-02-27 12:16:20 +000036#include "v8.h"
37
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +000038#include "api.h"
ager@chromium.org9085a012009-05-11 19:22:57 +000039#include "codegen.h"
kasperl@chromium.org061ef742009-02-27 12:16:20 +000040#include "log.h"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000041#include "isolate.h"
kasperl@chromium.org061ef742009-02-27 12:16:20 +000042#include "cctest.h"
ager@chromium.org9085a012009-05-11 19:22:57 +000043#include "disassembler.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000044#include "vm-state-inl.h"
kasperl@chromium.org061ef742009-02-27 12:16:20 +000045
46using v8::Function;
47using v8::Local;
48using v8::Object;
49using v8::Script;
50using v8::String;
51using v8::Value;
52
53using v8::internal::byte;
ager@chromium.org9085a012009-05-11 19:22:57 +000054using v8::internal::Address;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000055using v8::internal::Handle;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000056using v8::internal::Isolate;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000057using v8::internal::JSFunction;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000058using v8::internal::TickSample;
59
60
kasperl@chromium.org061ef742009-02-27 12:16:20 +000061static struct {
kasperl@chromium.org061ef742009-02-27 12:16:20 +000062 TickSample* sample;
ager@chromium.orge2902be2009-06-08 12:21:35 +000063} trace_env = { NULL };
kasperl@chromium.org061ef742009-02-27 12:16:20 +000064
65
ager@chromium.orge2902be2009-06-08 12:21:35 +000066static void InitTraceEnv(TickSample* sample) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +000067 trace_env.sample = sample;
68}
69
70
ager@chromium.org9085a012009-05-11 19:22:57 +000071static void DoTrace(Address fp) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000072 trace_env.sample->fp = fp;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000073 // sp is only used to define stack high bound
74 trace_env.sample->sp =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000075 reinterpret_cast<Address>(trace_env.sample) - 10240;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000076 trace_env.sample->Trace(Isolate::Current());
kasperl@chromium.org061ef742009-02-27 12:16:20 +000077}
78
79
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000080// Hide c_entry_fp to emulate situation when sampling is done while
81// pure JS code is being executed
ager@chromium.org9085a012009-05-11 19:22:57 +000082static void DoTraceHideCEntryFPAddress(Address fp) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000083 v8::internal::Address saved_c_frame_fp =
84 *(Isolate::Current()->c_entry_fp_address());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000085 CHECK(saved_c_frame_fp);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000086 *(Isolate::Current()->c_entry_fp_address()) = 0;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000087 DoTrace(fp);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000088 *(Isolate::Current()->c_entry_fp_address()) = saved_c_frame_fp;
kasperl@chromium.org061ef742009-02-27 12:16:20 +000089}
90
91
kasperl@chromium.org061ef742009-02-27 12:16:20 +000092// --- T r a c e E x t e n s i o n ---
93
94class TraceExtension : public v8::Extension {
95 public:
96 TraceExtension() : v8::Extension("v8/trace", kSource) { }
97 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000098 v8::Handle<String> name);
kasperl@chromium.org061ef742009-02-27 12:16:20 +000099 static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000100 static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000101 static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args);
102 static v8::Handle<v8::Value> JSEntrySPLevel2(const v8::Arguments& args);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000103 private:
ager@chromium.org9085a012009-05-11 19:22:57 +0000104 static Address GetFP(const v8::Arguments& args);
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000105 static const char* kSource;
106};
107
108
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000109const char* TraceExtension::kSource =
110 "native function trace();"
ager@chromium.orge2902be2009-06-08 12:21:35 +0000111 "native function js_trace();"
112 "native function js_entry_sp();"
113 "native function js_entry_sp_level2();";
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000114
115v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000116 v8::Handle<String> name) {
117 if (name->Equals(String::New("trace"))) {
118 return v8::FunctionTemplate::New(TraceExtension::Trace);
119 } else if (name->Equals(String::New("js_trace"))) {
120 return v8::FunctionTemplate::New(TraceExtension::JSTrace);
ager@chromium.orge2902be2009-06-08 12:21:35 +0000121 } else if (name->Equals(String::New("js_entry_sp"))) {
122 return v8::FunctionTemplate::New(TraceExtension::JSEntrySP);
123 } else if (name->Equals(String::New("js_entry_sp_level2"))) {
124 return v8::FunctionTemplate::New(TraceExtension::JSEntrySPLevel2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000125 } else {
126 CHECK(false);
127 return v8::Handle<v8::FunctionTemplate>();
128 }
129}
130
131
ager@chromium.org9085a012009-05-11 19:22:57 +0000132Address TraceExtension::GetFP(const v8::Arguments& args) {
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000133 // Convert frame pointer from encoding as smis in the arguments to a pointer.
134 CHECK_EQ(2, args.Length()); // Ignore second argument on 32-bit platform.
135#if defined(V8_HOST_ARCH_32_BIT)
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +0000136 Address fp = *reinterpret_cast<Address*>(*args[0]);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000137#elif defined(V8_HOST_ARCH_64_BIT)
138 int64_t low_bits = *reinterpret_cast<uint64_t*>(*args[0]) >> 32;
139 int64_t high_bits = *reinterpret_cast<uint64_t*>(*args[1]);
140 Address fp = reinterpret_cast<Address>(high_bits | low_bits);
141#else
142#error Host architecture is neither 32-bit nor 64-bit.
143#endif
ager@chromium.org9085a012009-05-11 19:22:57 +0000144 printf("Trace: %p\n", fp);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 return fp;
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000146}
147
148
149v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 DoTrace(GetFP(args));
151 return v8::Undefined();
152}
153
154
155v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
156 DoTraceHideCEntryFPAddress(GetFP(args));
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000157 return v8::Undefined();
158}
159
160
ager@chromium.orge2902be2009-06-08 12:21:35 +0000161static Address GetJsEntrySp() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000162 CHECK_NE(NULL, i::Isolate::Current()->thread_local_top());
163 return Isolate::js_entry_sp(i::Isolate::Current()->thread_local_top());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000164}
165
166
167v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) {
168 CHECK_NE(0, GetJsEntrySp());
169 return v8::Undefined();
170}
171
172
ager@chromium.orge2902be2009-06-08 12:21:35 +0000173v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2(
174 const v8::Arguments& args) {
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +0000175 v8::HandleScope scope(args.GetIsolate());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000176 const Address js_entry_sp = GetJsEntrySp();
177 CHECK_NE(0, js_entry_sp);
178 CompileRun("js_entry_sp();");
179 CHECK_EQ(js_entry_sp, GetJsEntrySp());
180 return v8::Undefined();
181}
182
183
kasperl@chromium.org061ef742009-02-27 12:16:20 +0000184static TraceExtension kTraceExtension;
185v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
186
187
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000188static bool IsAddressWithinFuncCode(JSFunction* function, Address addr) {
189 i::Code* code = function->code();
190 return code->contains(addr);
191}
192
193static bool IsAddressWithinFuncCode(const char* func_name, Address addr) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000194 v8::Local<v8::Value> func = CcTest::env()->Global()->Get(v8_str(func_name));
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000195 CHECK(func->IsFunction());
196 JSFunction* js_func = JSFunction::cast(*v8::Utils::OpenHandle(*func));
197 return IsAddressWithinFuncCode(js_func, addr);
ager@chromium.org9085a012009-05-11 19:22:57 +0000198}
199
200
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000201// This C++ function is called as a constructor, to grab the frame pointer
202// from the calling function. When this function runs, the stack contains
203// a C_Entry frame and a Construct frame above the calling function's frame.
204static v8::Handle<Value> construct_call(const v8::Arguments& args) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000205 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
206 i::StackFrameIterator frame_iterator(isolate);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000207 CHECK(frame_iterator.frame()->is_exit());
208 frame_iterator.Advance();
209 CHECK(frame_iterator.frame()->is_construct());
210 frame_iterator.Advance();
211 i::StackFrame* calling_frame = frame_iterator.frame();
212 CHECK(calling_frame->is_java_script());
ager@chromium.org9085a012009-05-11 19:22:57 +0000213
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000214#if defined(V8_HOST_ARCH_32_BIT)
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000215 int32_t low_bits = reinterpret_cast<int32_t>(calling_frame->fp());
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000216 args.This()->Set(v8_str("low_bits"), v8_num(low_bits >> 1));
217#elif defined(V8_HOST_ARCH_64_BIT)
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000218 uint64_t fp = reinterpret_cast<uint64_t>(calling_frame->fp());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +0000219 int32_t low_bits = static_cast<int32_t>(fp & 0xffffffff);
220 int32_t high_bits = static_cast<int32_t>(fp >> 32);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000221 args.This()->Set(v8_str("low_bits"), v8_num(low_bits));
222 args.This()->Set(v8_str("high_bits"), v8_num(high_bits));
223#else
224#error Host architecture is neither 32-bit nor 64-bit.
225#endif
226 return args.This();
227}
ager@chromium.org9085a012009-05-11 19:22:57 +0000228
ager@chromium.org9085a012009-05-11 19:22:57 +0000229
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000230// Use the API to create a JSFunction object that calls the above C++ function.
231void CreateFramePointerGrabberConstructor(const char* constructor_name) {
232 Local<v8::FunctionTemplate> constructor_template =
233 v8::FunctionTemplate::New(construct_call);
234 constructor_template->SetClassName(v8_str("FPGrabber"));
235 Local<Function> fun = constructor_template->GetFunction();
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000236 CcTest::env()->Global()->Set(v8_str(constructor_name), fun);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000237}
ager@chromium.org9085a012009-05-11 19:22:57 +0000238
239
240// Creates a global function named 'func_name' that calls the tracing
241// function 'trace_func_name' with an actual EBP register value,
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000242// encoded as one or two Smis.
ager@chromium.org9085a012009-05-11 19:22:57 +0000243static void CreateTraceCallerFunction(const char* func_name,
244 const char* trace_func_name) {
245 i::EmbeddedVector<char, 256> trace_call_buf;
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000246 i::OS::SNPrintF(trace_call_buf,
lrn@chromium.org303ada72010-10-27 09:33:13 +0000247 "function %s() {"
248 " fp = new FPGrabber();"
249 " %s(fp.low_bits, fp.high_bits);"
250 "}",
251 func_name, trace_func_name);
kmillikin@chromium.org3cdd9e12010-09-06 11:39:48 +0000252
253 // Create the FPGrabber function, which grabs the caller's frame pointer
254 // when called as a constructor.
255 CreateFramePointerGrabberConstructor("FPGrabber");
ager@chromium.org9085a012009-05-11 19:22:57 +0000256
257 // Compile the script.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000258 CompileRun(trace_call_buf.start());
ager@chromium.org9085a012009-05-11 19:22:57 +0000259}
260
261
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000262// This test verifies that stack tracing works when called during
263// execution of a native function called from JS code. In this case,
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000264// TickSample::Trace uses Isolate::c_entry_fp as a starting point for stack
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000265// walking.
ager@chromium.org9085a012009-05-11 19:22:57 +0000266TEST(CFromJSStackTrace) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000267 // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test.
268 i::FLAG_use_inlining = false;
ulan@chromium.org6ff65142012-03-21 09:52:17 +0000269
ager@chromium.org9085a012009-05-11 19:22:57 +0000270 TickSample sample;
ager@chromium.orge2902be2009-06-08 12:21:35 +0000271 InitTraceEnv(&sample);
ager@chromium.org9085a012009-05-11 19:22:57 +0000272
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000273 CcTest::InitializeVM(TRACE_EXTENSION);
274 v8::HandleScope scope(CcTest::isolate());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000275 // Create global function JSFuncDoTrace which calls
276 // extension function trace() with the current frame pointer value.
ager@chromium.org9085a012009-05-11 19:22:57 +0000277 CreateTraceCallerFunction("JSFuncDoTrace", "trace");
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000278 Local<Value> result = CompileRun(
ager@chromium.org9085a012009-05-11 19:22:57 +0000279 "function JSTrace() {"
280 " JSFuncDoTrace();"
281 "};\n"
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000282 "JSTrace();\n"
283 "true;");
284 CHECK(!result.IsEmpty());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000285 // When stack tracer is invoked, the stack should look as follows:
286 // script [JS]
287 // JSTrace() [JS]
288 // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi]
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000289 // trace(EBP) [native (extension)]
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000290 // DoTrace(EBP) [native]
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000291 // TickSample::Trace
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000292
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000293 CHECK(sample.has_external_callback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 CHECK_EQ(FUNCTION_ADDR(TraceExtension::Trace), sample.external_callback);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000295
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000296 // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000297 int base = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000298 CHECK_GT(sample.frames_count, base + 1);
jkummerow@chromium.org531dfe82012-03-20 13:01:16 +0000299
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000300 CHECK(IsAddressWithinFuncCode("JSFuncDoTrace", sample.stack[base + 0]));
301 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 1]));
ager@chromium.org9085a012009-05-11 19:22:57 +0000302}
303
304
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000305// This test verifies that stack tracing works when called during
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000306// execution of JS code. However, as calling TickSample::Trace requires
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000307// entering native code, we can only emulate pure JS by erasing
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000308// Isolate::c_entry_fp value. In this case, TickSample::Trace uses passed frame
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000309// pointer value as a starting point for stack walking.
ager@chromium.org9085a012009-05-11 19:22:57 +0000310TEST(PureJSStackTrace) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000311 // This test does not pass with inlining enabled since inlined functions
312 // don't appear in the stack trace.
313 i::FLAG_use_inlining = false;
314
ager@chromium.org9085a012009-05-11 19:22:57 +0000315 TickSample sample;
ager@chromium.orge2902be2009-06-08 12:21:35 +0000316 InitTraceEnv(&sample);
ager@chromium.org9085a012009-05-11 19:22:57 +0000317
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000318 CcTest::InitializeVM(TRACE_EXTENSION);
319 v8::HandleScope scope(CcTest::isolate());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000320 // Create global function JSFuncDoTrace which calls
321 // extension function js_trace() with the current frame pointer value.
ager@chromium.org9085a012009-05-11 19:22:57 +0000322 CreateTraceCallerFunction("JSFuncDoTrace", "js_trace");
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000323 Local<Value> result = CompileRun(
ager@chromium.org9085a012009-05-11 19:22:57 +0000324 "function JSTrace() {"
325 " JSFuncDoTrace();"
326 "};\n"
327 "function OuterJSTrace() {"
328 " JSTrace();"
329 "};\n"
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000330 "OuterJSTrace();\n"
331 "true;");
332 CHECK(!result.IsEmpty());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000333 // When stack tracer is invoked, the stack should look as follows:
334 // script [JS]
335 // OuterJSTrace() [JS]
336 // JSTrace() [JS]
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000337 // JSFuncDoTrace() [JS]
338 // js_trace(EBP) [native (extension)]
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000339 // DoTraceHideCEntryFPAddress(EBP) [native]
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000340 // TickSample::Trace
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000341 //
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000342
ulan@chromium.org77ca49a2013-04-22 09:43:56 +0000343 CHECK(sample.has_external_callback);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 CHECK_EQ(FUNCTION_ADDR(TraceExtension::JSTrace), sample.external_callback);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000345
ager@chromium.org9085a012009-05-11 19:22:57 +0000346 // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000347 int base = 0;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000348 CHECK_GT(sample.frames_count, base + 1);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000349 CHECK(IsAddressWithinFuncCode("JSTrace", sample.stack[base + 0]));
350 CHECK(IsAddressWithinFuncCode("OuterJSTrace", sample.stack[base + 1]));
ager@chromium.org9085a012009-05-11 19:22:57 +0000351}
352
353
ager@chromium.org3811b432009-10-28 14:53:37 +0000354static void CFuncDoTrace(byte dummy_parameter) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000355 Address fp;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000356#ifdef __GNUC__
ager@chromium.org9085a012009-05-11 19:22:57 +0000357 fp = reinterpret_cast<Address>(__builtin_frame_address(0));
ager@chromium.org3811b432009-10-28 14:53:37 +0000358#elif defined _MSC_VER
359 // Approximate a frame pointer address. We compile without base pointers,
360 // so we can't trust ebp/rbp.
361 fp = &dummy_parameter - 2 * sizeof(void*); // NOLINT
362#else
363#error Unexpected platform.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000364#endif
365 DoTrace(fp);
366}
367
368
369static int CFunc(int depth) {
370 if (depth <= 0) {
ager@chromium.org3811b432009-10-28 14:53:37 +0000371 CFuncDoTrace(0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000372 return 0;
373 } else {
374 return CFunc(depth - 1) + 1;
375 }
376}
377
378
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000379// This test verifies that stack tracing doesn't crash when called on
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000380// pure native code. TickSample::Trace only unrolls JS code, so we can't
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000381// get any meaningful info here.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000382TEST(PureCStackTrace) {
383 TickSample sample;
ager@chromium.orge2902be2009-06-08 12:21:35 +0000384 InitTraceEnv(&sample);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000385 CcTest::InitializeVM(TRACE_EXTENSION);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000386 // Check that sampler doesn't crash
387 CHECK_EQ(10, CFunc(10));
388}
389
390
ager@chromium.orge2902be2009-06-08 12:21:35 +0000391TEST(JsEntrySp) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000392 CcTest::InitializeVM(TRACE_EXTENSION);
393 v8::HandleScope scope(CcTest::isolate());
ager@chromium.orge2902be2009-06-08 12:21:35 +0000394 CHECK_EQ(0, GetJsEntrySp());
395 CompileRun("a = 1; b = a + 1;");
396 CHECK_EQ(0, GetJsEntrySp());
397 CompileRun("js_entry_sp();");
398 CHECK_EQ(0, GetJsEntrySp());
399 CompileRun("js_entry_sp_level2();");
400 CHECK_EQ(0, GetJsEntrySp());
401}