144bc7080a85cc25bff3b9b77cd53f7beffab711bkarlklose@chromium.org// Copyright 2011 the V8 project authors. All rights reserved.
23cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// Redistribution and use in source and binary forms, with or without
33cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// modification, are permitted provided that the following conditions are
43cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// met:
53cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//
63cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//     * Redistributions of source code must retain the above copyright
73cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//       notice, this list of conditions and the following disclaimer.
83cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//     * Redistributions in binary form must reproduce the above
93cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//       copyright notice, this list of conditions and the following
103cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//       disclaimer in the documentation and/or other materials provided
113cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//       with the distribution.
123cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//     * Neither the name of Google Inc. nor the names of its
133cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//       contributors may be used to endorse or promote products derived
143cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//       from this software without specific prior written permission.
153cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org//
163cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org//
28061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org// Tests of profiler-related functions from log.h
29061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org
30061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org#include <stdlib.h>
31061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org
32196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/v8.h"
33061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org
34196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/api.h"
35196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/codegen.h"
36196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/disassembler.h"
37196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/isolate.h"
38196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/log.h"
39196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/sampler.h"
40196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "src/vm-state-inl.h"
41196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "test/cctest/cctest.h"
42196eb601290dc49c3754da728dc58700dff2de1bmachenbach@chromium.org#include "test/cctest/trace-extension.h"
43061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org
44061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::Function;
45061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::Local;
46061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::Object;
47061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::Script;
48061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::String;
49061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::Value;
50061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org
51061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::internal::byte;
529085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgusing v8::internal::Address;
53061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::internal::Handle;
54ea88ce93dcb41a9200ec8747ae7642a5db1f4ce7sgjesse@chromium.orgusing v8::internal::Isolate;
55061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::internal::JSFunction;
56061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.orgusing v8::internal::TickSample;
57061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org
58061ef74c9b8acd038edf4b4355c50d097c8a9683kasperl@chromium.org
593a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgstatic bool IsAddressWithinFuncCode(JSFunction* function, Address addr) {
603a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  i::Code* code = function->code();
613a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  return code->contains(addr);
623a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org}
633a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org
64e0e1b0d3e70c933d36ed381d511e9fda39f2a751mstarzinger@chromium.org
65528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.orgstatic bool IsAddressWithinFuncCode(v8::Local<v8::Context> context,
66528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org                                    const char* func_name,
67528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org                                    Address addr) {
68528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::Local<v8::Value> func = context->Global()->Get(v8_str(func_name));
693a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  CHECK(func->IsFunction());
703a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  JSFunction* js_func = JSFunction::cast(*v8::Utils::OpenHandle(*func));
713a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org  return IsAddressWithinFuncCode(js_func, addr);
729085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
739085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
749085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
753cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// This C++ function is called as a constructor, to grab the frame pointer
763cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// from the calling function.  When this function runs, the stack contains
773cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// a C_Entry frame and a Construct frame above the calling function's frame.
781510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgstatic void construct_call(const v8::FunctionCallbackInfo<v8::Value>& args) {
79c03a1924dcc113678c0ebe58aa7d3c855a657719yangguo@chromium.org  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(args.GetIsolate());
80c03a1924dcc113678c0ebe58aa7d3c855a657719yangguo@chromium.org  i::StackFrameIterator frame_iterator(isolate);
813cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  CHECK(frame_iterator.frame()->is_exit());
823cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  frame_iterator.Advance();
833cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  CHECK(frame_iterator.frame()->is_construct());
843cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  frame_iterator.Advance();
853cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  i::StackFrame* calling_frame = frame_iterator.frame();
863cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  CHECK(calling_frame->is_java_script());
873cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org
883cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org#if defined(V8_HOST_ARCH_32_BIT)
894a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org  int32_t low_bits = reinterpret_cast<int32_t>(calling_frame->fp());
903cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  args.This()->Set(v8_str("low_bits"), v8_num(low_bits >> 1));
913cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org#elif defined(V8_HOST_ARCH_64_BIT)
924a1fe7d5e92fdb673d5f05d5ddf7b1ed703ba18dwhesse@chromium.org  uint64_t fp = reinterpret_cast<uint64_t>(calling_frame->fp());
93f05f2913e034b9332e55c02c9395e701725c02c1kmillikin@chromium.org  int32_t low_bits = static_cast<int32_t>(fp & 0xffffffff);
94f05f2913e034b9332e55c02c9395e701725c02c1kmillikin@chromium.org  int32_t high_bits = static_cast<int32_t>(fp >> 32);
953cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  args.This()->Set(v8_str("low_bits"), v8_num(low_bits));
963cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  args.This()->Set(v8_str("high_bits"), v8_num(high_bits));
973cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org#else
983cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org#error Host architecture is neither 32-bit nor 64-bit.
993cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org#endif
1001510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org  args.GetReturnValue().Set(args.This());
1013cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org}
1029085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1039085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1043cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// Use the API to create a JSFunction object that calls the above C++ function.
105528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.orgvoid CreateFramePointerGrabberConstructor(v8::Local<v8::Context> context,
106528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org                                          const char* constructor_name) {
1073cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org    Local<v8::FunctionTemplate> constructor_template =
1084f99be9ff2091451687891a05d99cc31990de709hpayer@chromium.org        v8::FunctionTemplate::New(context->GetIsolate(), construct_call);
1093cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org    constructor_template->SetClassName(v8_str("FPGrabber"));
1103cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org    Local<Function> fun = constructor_template->GetFunction();
111528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org    context->Global()->Set(v8_str(constructor_name), fun);
1123cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org}
1139085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1149085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1159085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org// Creates a global function named 'func_name' that calls the tracing
1169085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org// function 'trace_func_name' with an actual EBP register value,
1173cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org// encoded as one or two Smis.
118528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.orgstatic void CreateTraceCallerFunction(v8::Local<v8::Context> context,
119528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org                                      const char* func_name,
1209085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org                                      const char* trace_func_name) {
1219085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org  i::EmbeddedVector<char, 256> trace_call_buf;
12270ec1a2160dd946b9578d04d97d631a6d4ab4f8cbmeurer@chromium.org  i::SNPrintF(trace_call_buf,
12370ec1a2160dd946b9578d04d97d631a6d4ab4f8cbmeurer@chromium.org              "function %s() {"
12470ec1a2160dd946b9578d04d97d631a6d4ab4f8cbmeurer@chromium.org              "  fp = new FPGrabber();"
12570ec1a2160dd946b9578d04d97d631a6d4ab4f8cbmeurer@chromium.org              "  %s(fp.low_bits, fp.high_bits);"
12670ec1a2160dd946b9578d04d97d631a6d4ab4f8cbmeurer@chromium.org              "}",
12770ec1a2160dd946b9578d04d97d631a6d4ab4f8cbmeurer@chromium.org              func_name, trace_func_name);
1283cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org
1293cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  // Create the FPGrabber function, which grabs the caller's frame pointer
1303cdd9e13bac71e7c5b63da6962f8d30f6622db14kmillikin@chromium.org  // when called as a constructor.
131528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  CreateFramePointerGrabberConstructor(context, "FPGrabber");
1329085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1339085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org  // Compile the script.
134303ada708275d2d425b846fb237f1ba7598ee239lrn@chromium.org  CompileRun(trace_call_buf.start());
1359085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
1369085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1379085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
138df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org// This test verifies that stack tracing works when called during
139df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org// execution of a native function called from JS code. In this case,
140e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// TickSample::Trace uses Isolate::c_entry_fp as a starting point for stack
141df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org// walking.
1429085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgTEST(CFromJSStackTrace) {
14374f333bce721daf6b1f9d7d3d3faa623f77658d7vegorov@chromium.org  // BUG(1303) Inlining of JSFuncDoTrace() in JSTrace below breaks this test.
14474f333bce721daf6b1f9d7d3d3faa623f77658d7vegorov@chromium.org  i::FLAG_use_inlining = false;
1456ff651481ed0a881f176f6d55e26679ca359792bulan@chromium.org
1469085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org  TickSample sample;
14743c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  i::TraceExtension::InitTraceEnv(&sample);
1489085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
149e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org  v8::HandleScope scope(CcTest::isolate());
150528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
151528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::Context::Scope context_scope(context);
152528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org
153df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  // Create global function JSFuncDoTrace which calls
154df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  // extension function trace() with the current frame pointer value.
155528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  CreateTraceCallerFunction(context, "JSFuncDoTrace", "trace");
1565d8f0e6e7b477f422e3064bdf0dd5f2a23f75544kmillikin@chromium.org  Local<Value> result = CompileRun(
1579085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org      "function JSTrace() {"
1589085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org      "         JSFuncDoTrace();"
1599085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org      "};\n"
1605d8f0e6e7b477f422e3064bdf0dd5f2a23f75544kmillikin@chromium.org      "JSTrace();\n"
1615d8f0e6e7b477f422e3064bdf0dd5f2a23f75544kmillikin@chromium.org      "true;");
1625d8f0e6e7b477f422e3064bdf0dd5f2a23f75544kmillikin@chromium.org  CHECK(!result.IsEmpty());
163df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  // When stack tracer is invoked, the stack should look as follows:
164df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  // script [JS]
165df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  //   JSTrace() [JS]
166df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  //     JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi]
167c20610af4f0ca150977ca140a1174f98ee46f5aafschneider@chromium.org  //       trace(EBP) [native (extension)]
168df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  //         DoTrace(EBP) [native]
169e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org  //           TickSample::Trace
170a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
17177ca49ac05d25684c89442029c22f5b2bce94395ulan@chromium.org  CHECK(sample.has_external_callback);
17243c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::Trace), sample.external_callback);
173a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
174df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
17508e7569a10f8edbb47b8fe70a6e160a4e0c9cd30machenbach@chromium.org  unsigned base = 0;
176a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org  CHECK_GT(sample.frames_count, base + 1);
177531dfe85209e15c3e292569c285a5be54910da7cjkummerow@chromium.org
178528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  CHECK(IsAddressWithinFuncCode(
179528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org      context, "JSFuncDoTrace", sample.stack[base + 0]));
180528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 1]));
1819085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
1829085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
1839085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
184df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org// This test verifies that stack tracing works when called during
185e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// execution of JS code. However, as calling TickSample::Trace requires
186df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org// entering native code, we can only emulate pure JS by erasing
187e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// Isolate::c_entry_fp value. In this case, TickSample::Trace uses passed frame
188df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org// pointer value as a starting point for stack walking.
1899085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.orgTEST(PureJSStackTrace) {
190a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org  // This test does not pass with inlining enabled since inlined functions
191a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org  // don't appear in the stack trace.
192a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org  i::FLAG_use_inlining = false;
193a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
1949085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org  TickSample sample;
19543c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  i::TraceExtension::InitTraceEnv(&sample);
1969085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
197e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org  v8::HandleScope scope(CcTest::isolate());
198528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
199528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::Context::Scope context_scope(context);
200528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org
201df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  // Create global function JSFuncDoTrace which calls
202df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  // extension function js_trace() with the current frame pointer value.
203528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  CreateTraceCallerFunction(context, "JSFuncDoTrace", "js_trace");
2045d8f0e6e7b477f422e3064bdf0dd5f2a23f75544kmillikin@chromium.org  Local<Value> result = CompileRun(
2059085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org      "function JSTrace() {"
2069085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org      "         JSFuncDoTrace();"
2079085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org      "};\n"
2089085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org      "function OuterJSTrace() {"
2099085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org      "         JSTrace();"
2109085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org      "};\n"
2115d8f0e6e7b477f422e3064bdf0dd5f2a23f75544kmillikin@chromium.org      "OuterJSTrace();\n"
2125d8f0e6e7b477f422e3064bdf0dd5f2a23f75544kmillikin@chromium.org      "true;");
2135d8f0e6e7b477f422e3064bdf0dd5f2a23f75544kmillikin@chromium.org  CHECK(!result.IsEmpty());
214df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  // When stack tracer is invoked, the stack should look as follows:
215df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  // script [JS]
216df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  //   OuterJSTrace() [JS]
217df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  //     JSTrace() [JS]
218c20610af4f0ca150977ca140a1174f98ee46f5aafschneider@chromium.org  //       JSFuncDoTrace() [JS]
219c20610af4f0ca150977ca140a1174f98ee46f5aafschneider@chromium.org  //         js_trace(EBP) [native (extension)]
220df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  //           DoTraceHideCEntryFPAddress(EBP) [native]
221e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org  //             TickSample::Trace
222df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org  //
223a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
22477ca49ac05d25684c89442029c22f5b2bce94395ulan@chromium.org  CHECK(sample.has_external_callback);
22543c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  CHECK_EQ(FUNCTION_ADDR(i::TraceExtension::JSTrace), sample.external_callback);
226a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org
2279085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org  // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
22808e7569a10f8edbb47b8fe70a6e160a4e0c9cd30machenbach@chromium.org  unsigned base = 0;
229a55512615f5adc085d23bc8589d155c4b579fb7bkasperl@chromium.org  CHECK_GT(sample.frames_count, base + 1);
230528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  CHECK(IsAddressWithinFuncCode(context, "JSTrace", sample.stack[base + 0]));
231528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  CHECK(IsAddressWithinFuncCode(
232528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org      context, "OuterJSTrace", sample.stack[base + 1]));
2339085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org}
2349085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
2359085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org
2363811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.orgstatic void CFuncDoTrace(byte dummy_parameter) {
2379085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org  Address fp;
238bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org#ifdef __GNUC__
2399085a016223a6b72bf580d5781c93ec7b9e54422ager@chromium.org  fp = reinterpret_cast<Address>(__builtin_frame_address(0));
2403811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org#elif defined _MSC_VER
2413811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org  // Approximate a frame pointer address. We compile without base pointers,
2423811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org  // so we can't trust ebp/rbp.
2433811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org  fp = &dummy_parameter - 2 * sizeof(void*);  // NOLINT
2443811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org#else
2453811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org#error Unexpected platform.
246bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org#endif
24743c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  i::TraceExtension::DoTrace(fp);
248bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org}
249bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org
250bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org
251bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.orgstatic int CFunc(int depth) {
252bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org  if (depth <= 0) {
2533811b436bf328d2ace6fe79ce99aeda71f9f06d3ager@chromium.org    CFuncDoTrace(0);
254bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org    return 0;
255bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org  } else {
256bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org    return CFunc(depth - 1) + 1;
257bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org  }
258bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org}
259bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org
260bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org
261df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org// This test verifies that stack tracing doesn't crash when called on
262e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org// pure native code. TickSample::Trace only unrolls JS code, so we can't
263df7a284a293865a5fa9390be2e8f82ba3ac8598asgjesse@chromium.org// get any meaningful info here.
264bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.orgTEST(PureCStackTrace) {
265bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org  TickSample sample;
26643c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  i::TraceExtension::InitTraceEnv(&sample);
267528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::HandleScope scope(CcTest::isolate());
268528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
269528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::Context::Scope context_scope(context);
270bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org  // Check that sampler doesn't crash
271bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org  CHECK_EQ(10, CFunc(10));
272bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org}
273bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org
274bb29dc9819bb6f495ab6eddd2543965eb97a8e43ager@chromium.org
275e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.orgTEST(JsEntrySp) {
276e27d617298263725e8a48c2aa14029759b952623mstarzinger@chromium.org  v8::HandleScope scope(CcTest::isolate());
277528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::Local<v8::Context> context = CcTest::NewContext(TRACE_EXTENSION);
278528ce02b8680a3ab6d75c7079f180a4016c69b7amachenbach@chromium.org  v8::Context::Scope context_scope(context);
27943c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  CHECK_EQ(0, i::TraceExtension::GetJsEntrySp());
280e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org  CompileRun("a = 1; b = a + 1;");
28143c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  CHECK_EQ(0, i::TraceExtension::GetJsEntrySp());
282e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org  CompileRun("js_entry_sp();");
28343c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  CHECK_EQ(0, i::TraceExtension::GetJsEntrySp());
284e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org  CompileRun("js_entry_sp_level2();");
28543c51e51fafad9405752a3d7e953367531469575machenbach@chromium.org  CHECK_EQ(0, i::TraceExtension::GetJsEntrySp());
286e2902be65446e26fd63a3b4eab2f14257cf4ebafager@chromium.org}
287