v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
test-log-stack-tracer.cc
Go to the documentation of this file.
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // 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.
27 //
28 // Tests of profiler-related functions from log.h
29 
30 #include <stdlib.h>
31 
32 #include "v8.h"
33 
34 #include "api.h"
35 #include "cctest.h"
36 #include "codegen.h"
37 #include "disassembler.h"
38 #include "isolate.h"
39 #include "log.h"
40 #include "sampler.h"
41 #include "trace-extension.h"
42 #include "vm-state-inl.h"
43 
44 using v8::Function;
45 using v8::Local;
46 using v8::Object;
47 using v8::Script;
48 using v8::String;
49 using v8::Value;
50 
51 using v8::internal::byte;
57 
58 
59 static bool IsAddressWithinFuncCode(JSFunction* function, Address addr) {
60  i::Code* code = function->code();
61  return code->contains(addr);
62 }
63 
64 
65 static bool IsAddressWithinFuncCode(v8::Local<v8::Context> context,
66  const char* func_name,
67  Address addr) {
68  v8::Local<v8::Value> func = context->Global()->Get(v8_str(func_name));
69  CHECK(func->IsFunction());
70  JSFunction* js_func = JSFunction::cast(*v8::Utils::OpenHandle(*func));
71  return IsAddressWithinFuncCode(js_func, addr);
72 }
73 
74 
75 // This C++ function is called as a constructor, to grab the frame pointer
76 // from the calling function. When this function runs, the stack contains
77 // a C_Entry frame and a Construct frame above the calling function's frame.
78 static void construct_call(const v8::FunctionCallbackInfo<v8::Value>& args) {
79  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
80  i::StackFrameIterator frame_iterator(isolate);
81  CHECK(frame_iterator.frame()->is_exit());
82  frame_iterator.Advance();
83  CHECK(frame_iterator.frame()->is_construct());
84  frame_iterator.Advance();
85  i::StackFrame* calling_frame = frame_iterator.frame();
86  CHECK(calling_frame->is_java_script());
87 
88 #if defined(V8_HOST_ARCH_32_BIT)
89  int32_t low_bits = reinterpret_cast<int32_t>(calling_frame->fp());
90  args.This()->Set(v8_str("low_bits"), v8_num(low_bits >> 1));
91 #elif defined(V8_HOST_ARCH_64_BIT)
92  uint64_t fp = reinterpret_cast<uint64_t>(calling_frame->fp());
93  int32_t low_bits = static_cast<int32_t>(fp & 0xffffffff);
94  int32_t high_bits = static_cast<int32_t>(fp >> 32);
95  args.This()->Set(v8_str("low_bits"), v8_num(low_bits));
96  args.This()->Set(v8_str("high_bits"), v8_num(high_bits));
97 #else
98 #error Host architecture is neither 32-bit nor 64-bit.
99 #endif
100  args.GetReturnValue().Set(args.This());
101 }
102 
103 
104 // Use the API to create a JSFunction object that calls the above C++ function.
106  const char* constructor_name) {
107  Local<v8::FunctionTemplate> constructor_template =
108  v8::FunctionTemplate::New(context->GetIsolate(), construct_call);
109  constructor_template->SetClassName(v8_str("FPGrabber"));
110  Local<Function> fun = constructor_template->GetFunction();
111  context->Global()->Set(v8_str(constructor_name), fun);
112 }
113 
114 
115 // Creates a global function named 'func_name' that calls the tracing
116 // function 'trace_func_name' with an actual EBP register value,
117 // encoded as one or two Smis.
118 static void CreateTraceCallerFunction(v8::Local<v8::Context> context,
119  const char* func_name,
120  const char* trace_func_name) {
121  i::EmbeddedVector<char, 256> trace_call_buf;
122  i::OS::SNPrintF(trace_call_buf,
123  "function %s() {"
124  " fp = new FPGrabber();"
125  " %s(fp.low_bits, fp.high_bits);"
126  "}",
127  func_name, trace_func_name);
128 
129  // Create the FPGrabber function, which grabs the caller's frame pointer
130  // when called as a constructor.
131  CreateFramePointerGrabberConstructor(context, "FPGrabber");
132 
133  // Compile the script.
134  CompileRun(trace_call_buf.start());
135 }
136 
137 
138 // This test verifies that stack tracing works when called during
139 // execution of a native function called from JS code. In this case,
140 // TickSample::Trace uses Isolate::c_entry_fp as a starting point for stack
141 // walking.
142 TEST(CFromJSStackTrace) {
143  // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test.
144  i::FLAG_use_inlining = false;
145 
148 
150  v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
151  v8::Context::Scope context_scope(context);
152 
153  // Create global function JSFuncDoTrace which calls
154  // extension function trace() with the current frame pointer value.
155  CreateTraceCallerFunction(context, "JSFuncDoTrace", "trace");
156  Local<Value> result = CompileRun(
157  "function JSTrace() {"
158  " JSFuncDoTrace();"
159  "};\n"
160  "JSTrace();\n"
161  "true;");
162  CHECK(!result.IsEmpty());
163  // When stack tracer is invoked, the stack should look as follows:
164  // script [JS]
165  // JSTrace() [JS]
166  // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi]
167  // trace(EBP) [native (extension)]
168  // DoTrace(EBP) [native]
169  // TickSample::Trace
170 
173 
174  // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
175  int base = 0;
176  CHECK_GT(sample.frames_count, base + 1);
177 
178  CHECK(IsAddressWithinFuncCode(
179  context, "JSFuncDoTrace", sample.stack[base + 0]));
180  CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 1]));
181 }
182 
183 
184 // This test verifies that stack tracing works when called during
185 // execution of JS code. However, as calling TickSample::Trace requires
186 // entering native code, we can only emulate pure JS by erasing
187 // Isolate::c_entry_fp value. In this case, TickSample::Trace uses passed frame
188 // pointer value as a starting point for stack walking.
189 TEST(PureJSStackTrace) {
190  // This test does not pass with inlining enabled since inlined functions
191  // don't appear in the stack trace.
192  i::FLAG_use_inlining = false;
193 
196 
198  v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
199  v8::Context::Scope context_scope(context);
200 
201  // Create global function JSFuncDoTrace which calls
202  // extension function js_trace() with the current frame pointer value.
203  CreateTraceCallerFunction(context, "JSFuncDoTrace", "js_trace");
204  Local<Value> result = CompileRun(
205  "function JSTrace() {"
206  " JSFuncDoTrace();"
207  "};\n"
208  "function OuterJSTrace() {"
209  " JSTrace();"
210  "};\n"
211  "OuterJSTrace();\n"
212  "true;");
213  CHECK(!result.IsEmpty());
214  // When stack tracer is invoked, the stack should look as follows:
215  // script [JS]
216  // OuterJSTrace() [JS]
217  // JSTrace() [JS]
218  // JSFuncDoTrace() [JS]
219  // js_trace(EBP) [native (extension)]
220  // DoTraceHideCEntryFPAddress(EBP) [native]
221  // TickSample::Trace
222  //
223 
226 
227  // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
228  int base = 0;
229  CHECK_GT(sample.frames_count, base + 1);
230  CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 0]));
231  CHECK(IsAddressWithinFuncCode(
232  context, "OuterJSTrace", sample.stack[base + 1]));
233 }
234 
235 
236 static void CFuncDoTrace(byte dummy_parameter) {
237  Address fp;
238 #ifdef __GNUC__
239  fp = reinterpret_cast<Address>(__builtin_frame_address(0));
240 #elif defined _MSC_VER
241  // Approximate a frame pointer address. We compile without base pointers,
242  // so we can't trust ebp/rbp.
243  fp = &dummy_parameter - 2 * sizeof(void*); // NOLINT
244 #else
245 #error Unexpected platform.
246 #endif
248 }
249 
250 
251 static int CFunc(int depth) {
252  if (depth <= 0) {
253  CFuncDoTrace(0);
254  return 0;
255  } else {
256  return CFunc(depth - 1) + 1;
257  }
258 }
259 
260 
261 // This test verifies that stack tracing doesn't crash when called on
262 // pure native code. TickSample::Trace only unrolls JS code, so we can't
263 // get any meaningful info here.
264 TEST(PureCStackTrace) {
268  v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
269  v8::Context::Scope context_scope(context);
270  // Check that sampler doesn't crash
271  CHECK_EQ(10, CFunc(10));
272 }
273 
274 
275 TEST(JsEntrySp) {
277  v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
278  v8::Context::Scope context_scope(context);
280  CompileRun("a = 1; b = a + 1;");
282  CompileRun("js_entry_sp();");
284  CompileRun("js_entry_sp_level2();");
286 }
byte * Address
Definition: globals.h:186
unsigned char byte
Definition: disasm.h:33
#define CHECK_EQ(expected, value)
Definition: checks.h:252
Definition: v8.h:1407
V8_INLINE Isolate * GetIsolate() const
Definition: v8.h:6061
#define CHECK_GT(a, b)
Definition: checks.h:260
V8_INLINE ReturnValue< T > GetReturnValue() const
Definition: v8.h:6067
TickSample * sample
Address external_callback
Definition: sampler.h:68
kSerializedDataOffset Object
Definition: objects-inl.h:5016
int int32_t
Definition: unicode.cc:47
#define CHECK(condition)
Definition: checks.h:75
static void InitTraceEnv(TickSample *sample)
static v8::Local< v8::Context > NewContext(CcTestExtensionFlags extensions, v8::Isolate *isolate=CcTest::isolate())
Definition: cctest.cc:90
v8::Isolate * GetIsolate()
Definition: api.cc:5233
void SetClassName(Handle< String > name)
Definition: api.cc:1250
bool contains(byte *pc)
Definition: objects-inl.h:5892
uint8_t byte
Definition: globals.h:185
HANDLE HANDLE LPSTACKFRAME64 StackFrame
static void JSTrace(const v8::FunctionCallbackInfo< v8::Value > &args)
T * start() const
Definition: utils.h:426
static Local< FunctionTemplate > New(Isolate *isolate, FunctionCallback callback=0, Handle< Value > data=Handle< Value >(), Handle< Signature > signature=Handle< Signature >(), int length=0)
Definition: api.cc:942
Local< Object > Global()
Definition: api.cc:5239
V8_INLINE Local< Object > This() const
Definition: v8.h:6042
Address stack[kMaxFramesCount]
Definition: sampler.h:71
void CreateFramePointerGrabberConstructor(v8::Local< v8::Context > context, const char *constructor_name)
static v8::internal::Handle< To > OpenHandle(v8::Local< From > handle)
Definition: api.h:308
static int SNPrintF(Vector< char > str, const char *format,...)
V8_INLINE bool IsEmpty() const
Definition: v8.h:248
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter trace hydrogen to given file name trace inlining decisions trace store elimination trace all use positions trace global value numbering trace hydrogen escape analysis trace the tracking of allocation sites trace map generalization environment for every instruction deoptimize every n garbage collections put a break point before deoptimizing deoptimize uncommon cases use on stack replacement trace array bounds check elimination perform array index dehoisting use load elimination use store elimination use constant folding eliminate unreachable code number of stress runs when picking a function to watch for shared function not JSFunction itself flushes the cache of optimized code for closures on every GC functions with arguments object maximum number of escape analysis fix point iterations allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms concurrent on stack replacement do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes number of stack frames inspected by the profiler percentage of ICs that must have type info to allow optimization extra verbose compilation tracing generate extra code(assertions) for debugging") DEFINE_bool(code_comments
Local< Function > GetFunction()
Definition: api.cc:5299
static void DoTrace(Address fp)
TEST(CFromJSStackTrace)
static void Trace(const v8::FunctionCallbackInfo< v8::Value > &args)
const Register fp
#define FUNCTION_ADDR(f)
Definition: globals.h:345
Definition: v8.h:124
static v8::Isolate * isolate()
Definition: cctest.h:96