18b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch// Copyright 2011 the V8 project authors. All rights reserved. 29ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// Redistribution and use in source and binary forms, with or without 39ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// modification, are permitted provided that the following conditions are 49ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// met: 59ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// 69ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// * Redistributions of source code must retain the above copyright 79ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// notice, this list of conditions and the following disclaimer. 89ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// * Redistributions in binary form must reproduce the above 99ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// copyright notice, this list of conditions and the following 109ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// disclaimer in the documentation and/or other materials provided 119ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// with the distribution. 129ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// * Neither the name of Google Inc. nor the names of its 139ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// contributors may be used to endorse or promote products derived 149ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// from this software without specific prior written permission. 159ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// 169ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 179ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 189ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 199ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 209ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 219ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 229ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 239ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 249ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 259ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 269ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Tests of profiler-related functions from log.h 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdlib.h> 31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/v8.h" 33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/api.h" 35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h" 36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/disassembler.h" 37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/isolate.h" 38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/log.h" 39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/sampler.h" 40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/vm-state-inl.h" 41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "test/cctest/cctest.h" 42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "test/cctest/trace-extension.h" 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Function; 45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Local; 46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Object; 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Script; 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::String; 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Value; 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::byte; 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::Address; 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::Handle; 5444f0eee88ff00398ff7f715fab053374d808c90dSteve Blockusing v8::internal::Isolate; 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::JSFunction; 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::TickSample; 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 59e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochstatic bool IsAddressWithinFuncCode(JSFunction* function, Address addr) { 60e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch i::Code* code = function->code(); 61e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch return code->contains(addr); 62e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch} 63e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic bool IsAddressWithinFuncCode(v8::Local<v8::Context> context, 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch const char* func_name, 67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Address addr) { 68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::Local<v8::Value> func = context->Global()->Get(v8_str(func_name)); 69e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch CHECK(func->IsFunction()); 70e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch JSFunction* js_func = JSFunction::cast(*v8::Utils::OpenHandle(*func)); 71e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch return IsAddressWithinFuncCode(js_func, addr); 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 759ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// This C++ function is called as a constructor, to grab the frame pointer 769ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// from the calling function. When this function runs, the stack contains 779ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// a C_Entry frame and a Construct frame above the calling function's frame. 78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void construct_call(const v8::FunctionCallbackInfo<v8::Value>& args) { 79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate()); 80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch i::StackFrameIterator frame_iterator(isolate); 819ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick CHECK(frame_iterator.frame()->is_exit()); 829ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick frame_iterator.Advance(); 839ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick CHECK(frame_iterator.frame()->is_construct()); 849ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick frame_iterator.Advance(); 859ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick i::StackFrame* calling_frame = frame_iterator.frame(); 869ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick CHECK(calling_frame->is_java_script()); 879ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 889ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#if defined(V8_HOST_ARCH_32_BIT) 890d5e116f6aee03185f237311a943491bb079a768Kristian Monsen int32_t low_bits = reinterpret_cast<int32_t>(calling_frame->fp()); 909ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick args.This()->Set(v8_str("low_bits"), v8_num(low_bits >> 1)); 919ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#elif defined(V8_HOST_ARCH_64_BIT) 920d5e116f6aee03185f237311a943491bb079a768Kristian Monsen uint64_t fp = reinterpret_cast<uint64_t>(calling_frame->fp()); 93f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch int32_t low_bits = static_cast<int32_t>(fp & 0xffffffff); 94f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch int32_t high_bits = static_cast<int32_t>(fp >> 32); 959ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick args.This()->Set(v8_str("low_bits"), v8_num(low_bits)); 969ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick args.This()->Set(v8_str("high_bits"), v8_num(high_bits)); 979ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#else 989ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#error Host architecture is neither 32-bit nor 64-bit. 999ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#endif 100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch args.GetReturnValue().Set(args.This()); 1019ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick} 102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1049ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// Use the API to create a JSFunction object that calls the above C++ function. 105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid CreateFramePointerGrabberConstructor(v8::Local<v8::Context> context, 106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch const char* constructor_name) { 1079ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Local<v8::FunctionTemplate> constructor_template = 108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::FunctionTemplate::New(context->GetIsolate(), construct_call); 1099ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick constructor_template->SetClassName(v8_str("FPGrabber")); 1109ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick Local<Function> fun = constructor_template->GetFunction(); 111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch context->Global()->Set(v8_str(constructor_name), fun); 1129ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick} 113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Creates a global function named 'func_name' that calls the tracing 116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// function 'trace_func_name' with an actual EBP register value, 1179ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// encoded as one or two Smis. 118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochstatic void CreateTraceCallerFunction(v8::Local<v8::Context> context, 119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch const char* func_name, 120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block const char* trace_func_name) { 121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block i::EmbeddedVector<char, 256> trace_call_buf; 122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch i::SNPrintF(trace_call_buf, 123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "function %s() {" 124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch " fp = new FPGrabber();" 125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch " %s(fp.low_bits, fp.high_bits);" 126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "}", 127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch func_name, trace_func_name); 1289ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick 1299ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // Create the FPGrabber function, which grabs the caller's frame pointer 1309ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick // when called as a constructor. 131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CreateFramePointerGrabberConstructor(context, "FPGrabber"); 132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Compile the script. 1345913587db4c6bab03d97bfe44b06289fd6d7270dJohn Reck CompileRun(trace_call_buf.start()); 135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1386ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// This test verifies that stack tracing works when called during 1396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// execution of a native function called from JS code. In this case, 140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// TickSample::Trace uses Isolate::c_entry_fp as a starting point for stack 1416ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// walking. 142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(CFromJSStackTrace) { 1438b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test. 1448b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch i::FLAG_use_inlining = false; 1458b112d2025046f85ef7f6be087c6129c872ebad2Ben Murdoch 146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block TickSample sample; 147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch i::TraceExtension::InitTraceEnv(&sample); 148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::HandleScope scope(CcTest::isolate()); 150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION); 151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::Context::Scope context_scope(context); 152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1536ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Create global function JSFuncDoTrace which calls 1546ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // extension function trace() with the current frame pointer value. 155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CreateTraceCallerFunction(context, "JSFuncDoTrace", "trace"); 1566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Local<Value> result = CompileRun( 157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "function JSTrace() {" 158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block " JSFuncDoTrace();" 159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "};\n" 1606ded16be15dd865a9b21ea304d5273c8be299c87Steve Block "JSTrace();\n" 1616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block "true;"); 1626ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CHECK(!result.IsEmpty()); 1636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // When stack tracer is invoked, the stack should look as follows: 1646ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // script [JS] 1656ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // JSTrace() [JS] 1666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi] 1670d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // trace(EBP) [native (extension)] 1686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // DoTrace(EBP) [native] 169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // TickSample::Trace 170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 17144f0eee88ff00398ff7f715fab053374d808c90dSteve Block CHECK(sample.has_external_callback); 172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::Trace), sample.external_callback); 173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 1746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace" 175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch unsigned base = 0; 176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CHECK_GT(sample.frames_count, base + 1); 1773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK(IsAddressWithinFuncCode( 179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch context, "JSFuncDoTrace", sample.stack[base + 0])); 180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 1])); 181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1846ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// This test verifies that stack tracing works when called during 185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// execution of JS code. However, as calling TickSample::Trace requires 1866ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// entering native code, we can only emulate pure JS by erasing 187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Isolate::c_entry_fp value. In this case, TickSample::Trace uses passed frame 1886ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// pointer value as a starting point for stack walking. 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(PureJSStackTrace) { 190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // This test does not pass with inlining enabled since inlined functions 191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch // don't appear in the stack trace. 192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch i::FLAG_use_inlining = false; 193b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block TickSample sample; 195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch i::TraceExtension::InitTraceEnv(&sample); 196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::HandleScope scope(CcTest::isolate()); 198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION); 199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::Context::Scope context_scope(context); 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2016ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // Create global function JSFuncDoTrace which calls 2026ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // extension function js_trace() with the current frame pointer value. 203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CreateTraceCallerFunction(context, "JSFuncDoTrace", "js_trace"); 2046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block Local<Value> result = CompileRun( 205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "function JSTrace() {" 206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block " JSFuncDoTrace();" 207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "};\n" 208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "function OuterJSTrace() {" 209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block " JSTrace();" 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block "};\n" 2116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block "OuterJSTrace();\n" 2126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block "true;"); 2136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block CHECK(!result.IsEmpty()); 2146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // When stack tracer is invoked, the stack should look as follows: 2156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // script [JS] 2166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // OuterJSTrace() [JS] 2176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // JSTrace() [JS] 2180d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // JSFuncDoTrace() [JS] 2190d5e116f6aee03185f237311a943491bb079a768Kristian Monsen // js_trace(EBP) [native (extension)] 2206ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // DoTraceHideCEntryFPAddress(EBP) [native] 221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // TickSample::Trace 2226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block // 223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 22444f0eee88ff00398ff7f715fab053374d808c90dSteve Block CHECK(sample.has_external_callback); 225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::JSTrace), sample.external_callback); 226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch 227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" 228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch unsigned base = 0; 229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch CHECK_GT(sample.frames_count, base + 1); 230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 0])); 231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK(IsAddressWithinFuncCode( 232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch context, "OuterJSTrace", sample.stack[base + 1])); 233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 236d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void CFuncDoTrace(byte dummy_parameter) { 237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Address fp; 238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef __GNUC__ 239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block fp = reinterpret_cast<Address>(__builtin_frame_address(0)); 240d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#elif defined _MSC_VER 241d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // Approximate a frame pointer address. We compile without base pointers, 242d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block // so we can't trust ebp/rbp. 243d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block fp = &dummy_parameter - 2 * sizeof(void*); // NOLINT 244d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#else 245d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#error Unexpected platform. 246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif 247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch i::TraceExtension::DoTrace(fp); 248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic int CFunc(int depth) { 252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if (depth <= 0) { 253d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block CFuncDoTrace(0); 254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return 0; 255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } else { 256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return CFunc(depth - 1) + 1; 257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block } 258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 2616ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// This test verifies that stack tracing doesn't crash when called on 262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// pure native code. TickSample::Trace only unrolls JS code, so we can't 2636ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// get any meaningful info here. 264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(PureCStackTrace) { 265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block TickSample sample; 266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch i::TraceExtension::InitTraceEnv(&sample); 267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::HandleScope scope(CcTest::isolate()); 268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION); 269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::Context::Scope context_scope(context); 270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block // Check that sampler doesn't crash 271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CHECK_EQ(10, CFunc(10)); 272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(JsEntrySp) { 276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::HandleScope scope(CcTest::isolate()); 277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION); 278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8::Context::Scope context_scope(context); 279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK_EQ(0, i::TraceExtension::GetJsEntrySp()); 280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CompileRun("a = 1; b = a + 1;"); 281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK_EQ(0, i::TraceExtension::GetJsEntrySp()); 282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CompileRun("js_entry_sp();"); 283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK_EQ(0, i::TraceExtension::GetJsEntrySp()); 284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block CompileRun("js_entry_sp_level2();"); 285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch CHECK_EQ(0, i::TraceExtension::GetJsEntrySp()); 286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} 287