test-log-stack-tracer.cc revision 9ac36c9faca11611ada13b4054edbaa0738661d0
19ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// Copyright 2010 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#ifdef ENABLE_LOGGING_AND_PROFILING
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include <stdlib.h>
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "v8.h"
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "codegen.h"
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "log.h"
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "top.h"
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "cctest.h"
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "disassembler.h"
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#include "register-allocator-inl.h"
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Function;
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Local;
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Object;
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Script;
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::String;
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::Value;
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::byte;
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::Address;
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::Handle;
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::JSFunction;
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::StackTracer;
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::TickSample;
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockusing v8::internal::Top;
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocknamespace i = v8::internal;
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic v8::Persistent<v8::Context> env;
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic struct {
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TickSample* sample;
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block} trace_env = { NULL };
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void InitTraceEnv(TickSample* sample) {
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  trace_env.sample = sample;
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void DoTrace(Address fp) {
75d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  trace_env.sample->fp = fp;
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // sp is only used to define stack high bound
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  trace_env.sample->sp =
78d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke      reinterpret_cast<Address>(trace_env.sample) - 10240;
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  StackTracer::Trace(trace_env.sample);
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Hide c_entry_fp to emulate situation when sampling is done while
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// pure JS code is being executed
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void DoTraceHideCEntryFPAddress(Address fp) {
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address());
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(saved_c_frame_fp);
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(Top::c_entry_fp_address()) = 0;
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DoTrace(fp);
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  *(Top::c_entry_fp_address()) = saved_c_frame_fp;
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// --- T r a c e   E x t e n s i o n ---
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass TraceExtension : public v8::Extension {
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block public:
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TraceExtension() : v8::Extension("v8/trace", kSource) { }
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      v8::Handle<String> name);
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args);
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static v8::Handle<v8::Value> JSEntrySPLevel2(const v8::Arguments& args);
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block private:
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static Address GetFP(const v8::Arguments& args);
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  static const char* kSource;
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block};
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockconst char* TraceExtension::kSource =
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    "native function trace();"
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    "native function js_trace();"
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    "native function js_entry_sp();"
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    "native function js_entry_sp_level2();";
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockv8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction(
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    v8::Handle<String> name) {
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (name->Equals(String::New("trace"))) {
120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return v8::FunctionTemplate::New(TraceExtension::Trace);
121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (name->Equals(String::New("js_trace"))) {
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return v8::FunctionTemplate::New(TraceExtension::JSTrace);
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (name->Equals(String::New("js_entry_sp"))) {
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return v8::FunctionTemplate::New(TraceExtension::JSEntrySP);
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else if (name->Equals(String::New("js_entry_sp_level2"))) {
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return v8::FunctionTemplate::New(TraceExtension::JSEntrySPLevel2);
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    CHECK(false);
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return v8::Handle<v8::FunctionTemplate>();
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockAddress TraceExtension::GetFP(const v8::Arguments& args) {
1359ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Convert frame pointer from encoding as smis in the arguments to a pointer.
1369ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  CHECK_EQ(2, args.Length());  // Ignore second argument on 32-bit platform.
1379ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#if defined(V8_HOST_ARCH_32_BIT)
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address fp = *reinterpret_cast<Address*>(*args[0]);
1399ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#elif defined(V8_HOST_ARCH_64_BIT)
1409ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  int64_t low_bits = *reinterpret_cast<uint64_t*>(*args[0]) >> 32;
1419ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  int64_t high_bits = *reinterpret_cast<uint64_t*>(*args[1]);
1429ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  Address fp = reinterpret_cast<Address>(high_bits | low_bits);
1439ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#else
1449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#error Host architecture is neither 32-bit nor 64-bit.
1459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#endif
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  printf("Trace: %p\n", fp);
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return fp;
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockv8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) {
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DoTrace(GetFP(args));
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return v8::Undefined();
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockv8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) {
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DoTraceHideCEntryFPAddress(GetFP(args));
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return v8::Undefined();
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic Address GetJsEntrySp() {
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(NULL, Top::GetCurrentThread());
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return Top::js_entry_sp(Top::GetCurrentThread());
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockv8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) {
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(0, GetJsEntrySp());
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return v8::Undefined();
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockv8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2(
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const v8::Arguments& args) {
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  const Address js_entry_sp = GetJsEntrySp();
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_NE(0, js_entry_sp);
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CompileRun("js_entry_sp();");
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(js_entry_sp, GetJsEntrySp());
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return v8::Undefined();
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic TraceExtension kTraceExtension;
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockv8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension);
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void InitializeVM() {
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (env.IsEmpty()) {
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    v8::HandleScope scope;
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    const char* extensions[] = { "v8/trace" };
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    v8::ExtensionConfiguration config(1, extensions);
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    env = v8::Context::New(&config);
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  env->Enter();
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic Handle<JSFunction> CompileFunction(const char* source) {
2036ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Handle<JSFunction> result(JSFunction::cast(
2046ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      *v8::Utils::OpenHandle(*Script::Compile(String::New(source)))));
2056ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  return result;
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic Local<Value> GetGlobalProperty(const char* name) {
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return env->Global()->Get(String::New(name));
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic Handle<JSFunction> GetGlobalJSFunction(const char* name) {
2156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Handle<JSFunction> result(JSFunction::cast(
2166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      *v8::Utils::OpenHandle(*GetGlobalProperty(name))));
2176ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  return result;
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
221f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarkestatic void CheckObjectIsJSFunction(const char* func_name,
222f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke                                    Address addr) {
223f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  i::Object* obj = reinterpret_cast<i::Object*>(addr);
224f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CHECK(obj->IsJSFunction());
225f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CHECK(JSFunction::cast(obj)->shared()->name()->IsString());
226f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  i::SmartPointer<char> found_name =
227f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke      i::String::cast(
228f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke          JSFunction::cast(
229f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke              obj)->shared()->name())->ToCString();
230f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CHECK_EQ(func_name, *found_name);
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void SetGlobalProperty(const char* name, Local<Value> value) {
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  env->Global()->Set(String::New(name), value);
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic Handle<v8::internal::String> NewString(const char* s) {
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return i::Factory::NewStringFromAscii(i::CStrVector(s));
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2449ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// This C++ function is called as a constructor, to grab the frame pointer
2459ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// from the calling function.  When this function runs, the stack contains
2469ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// a C_Entry frame and a Construct frame above the calling function's frame.
2479ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrickstatic v8::Handle<Value> construct_call(const v8::Arguments& args) {
2489ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  i::StackFrameIterator frame_iterator;
2499ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  CHECK(frame_iterator.frame()->is_exit());
2509ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  frame_iterator.Advance();
2519ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  CHECK(frame_iterator.frame()->is_construct());
2529ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  frame_iterator.Advance();
2539ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  i::StackFrame* calling_frame = frame_iterator.frame();
2549ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  CHECK(calling_frame->is_java_script());
2559ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
2569ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#if defined(V8_HOST_ARCH_32_BIT)
2579ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  int32_t low_bits = reinterpret_cast<intptr_t>(calling_frame->fp());
2589ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  args.This()->Set(v8_str("low_bits"), v8_num(low_bits >> 1));
2599ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#elif defined(V8_HOST_ARCH_64_BIT)
2609ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  int32_t low_bits = reinterpret_cast<uintptr_t>(calling_frame->fp());
2619ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  int32_t high_bits = reinterpret_cast<uintptr_t>(calling_frame->fp()) >> 32;
2629ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  args.This()->Set(v8_str("low_bits"), v8_num(low_bits));
2639ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  args.This()->Set(v8_str("high_bits"), v8_num(high_bits));
2649ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#else
2659ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#error Host architecture is neither 32-bit nor 64-bit.
2669ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick#endif
2679ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  return args.This();
2689ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick}
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
2719ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// Use the API to create a JSFunction object that calls the above C++ function.
2729ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrickvoid CreateFramePointerGrabberConstructor(const char* constructor_name) {
2739ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    Local<v8::FunctionTemplate> constructor_template =
2749ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick        v8::FunctionTemplate::New(construct_call);
2759ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    constructor_template->SetClassName(v8_str("FPGrabber"));
2769ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    Local<Function> fun = constructor_template->GetFunction();
2779ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick    env->Global()->Set(v8_str(constructor_name), fun);
2789ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick}
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// Creates a global function named 'func_name' that calls the tracing
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block// function 'trace_func_name' with an actual EBP register value,
2839ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick// encoded as one or two Smis.
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic void CreateTraceCallerFunction(const char* func_name,
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                                      const char* trace_func_name) {
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  i::EmbeddedVector<char, 256> trace_call_buf;
2879ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  i::OS::SNPrintF(trace_call_buf,
2889ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                  "fp = new FPGrabber(); %s(fp.low_bits, fp.high_bits);",
2899ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick                  trace_func_name);
2909ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick
2919ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // Create the FPGrabber function, which grabs the caller's frame pointer
2929ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  // when called as a constructor.
2939ac36c9faca11611ada13b4054edbaa0738661d0Iain Merrick  CreateFramePointerGrabberConstructor("FPGrabber");
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Compile the script.
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Handle<JSFunction> func = CompileFunction(trace_call_buf.start());
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(!func.is_null());
298f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  func->shared()->set_name(*NewString(func_name));
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef DEBUG
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::internal::Code* func_code = func->code();
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK(func_code->IsCode());
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  func_code->Print();
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  SetGlobalProperty(func_name, v8::ToApi<Value>(func));
3076ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  CHECK_EQ(*func, *GetGlobalJSFunction(func_name));
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3116ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// This test verifies that stack tracing works when called during
3126ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// execution of a native function called from JS code. In this case,
3136ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// StackTracer uses Top::c_entry_fp as a starting point for stack
3146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// walking.
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(CFromJSStackTrace) {
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TickSample sample;
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitTraceEnv(&sample);
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitializeVM();
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
3216ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Create global function JSFuncDoTrace which calls
3226ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // extension function trace() with the current frame pointer value.
323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CreateTraceCallerFunction("JSFuncDoTrace", "trace");
3246ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Local<Value> result = CompileRun(
325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function JSTrace() {"
326a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "         JSFuncDoTrace();"
327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "};\n"
3286ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      "JSTrace();\n"
3296ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      "true;");
3306ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  CHECK(!result.IsEmpty());
3316ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // When stack tracer is invoked, the stack should look as follows:
3326ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // script [JS]
3336ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //   JSTrace() [JS]
3346ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //     JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi]
3356ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //       trace(EBP encoded as Smi) [native (extension)]
3366ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //         DoTrace(EBP) [native]
3376ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //           StackTracer::Trace
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_GT(sample.frames_count, 1);
3396ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Stack tracing will start from the first JS function, i.e. "JSFuncDoTrace"
340f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CheckObjectIsJSFunction("JSFuncDoTrace", sample.stack[0]);
341f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CheckObjectIsJSFunction("JSTrace", sample.stack[1]);
342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
3456ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// This test verifies that stack tracing works when called during
3466ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// execution of JS code. However, as calling StackTracer requires
3476ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// entering native code, we can only emulate pure JS by erasing
3486ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// Top::c_entry_fp value. In this case, StackTracer uses passed frame
3496ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// pointer value as a starting point for stack walking.
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(PureJSStackTrace) {
351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TickSample sample;
352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitTraceEnv(&sample);
353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitializeVM();
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
3566ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // Create global function JSFuncDoTrace which calls
3576ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // extension function js_trace() with the current frame pointer value.
358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CreateTraceCallerFunction("JSFuncDoTrace", "js_trace");
3596ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  Local<Value> result = CompileRun(
360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function JSTrace() {"
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "         JSFuncDoTrace();"
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "};\n"
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "function OuterJSTrace() {"
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "         JSTrace();"
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      "};\n"
3666ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      "OuterJSTrace();\n"
3676ded16be15dd865a9b21ea304d5273c8be299c87Steve Block      "true;");
3686ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  CHECK(!result.IsEmpty());
3696ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // When stack tracer is invoked, the stack should look as follows:
3706ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // script [JS]
3716ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //   OuterJSTrace() [JS]
3726ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //     JSTrace() [JS]
3736ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //       JSFuncDoTrace() [JS] [captures EBP value and encodes it as Smi]
3746ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //         js_trace(EBP encoded as Smi) [native (extension)]
3756ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //           DoTraceHideCEntryFPAddress(EBP) [native]
3766ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //             StackTracer::Trace
3776ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  //
3786ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // The last JS function called. It is only visible through
3796ded16be15dd865a9b21ea304d5273c8be299c87Steve Block  // sample.function, as its return address is above captured EBP value.
380d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke  CHECK_EQ(GetGlobalJSFunction("JSFuncDoTrace")->address(),
381d91b9f7d46489a9ee00f9cb415630299c76a502bLeon Clarke           sample.function);
382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_GT(sample.frames_count, 1);
383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace"
384f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CheckObjectIsJSFunction("JSTrace", sample.stack[0]);
385f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke  CheckObjectIsJSFunction("OuterJSTrace", sample.stack[1]);
386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
389d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockstatic void CFuncDoTrace(byte dummy_parameter) {
390a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  Address fp;
391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#ifdef __GNUC__
392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  fp = reinterpret_cast<Address>(__builtin_frame_address(0));
393d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#elif defined _MSC_VER
394d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // Approximate a frame pointer address. We compile without base pointers,
395d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  // so we can't trust ebp/rbp.
396d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  fp = &dummy_parameter - 2 * sizeof(void*);  // NOLINT
397d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#else
398d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block#error Unexpected platform.
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif
400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  DoTrace(fp);
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockstatic int CFunc(int depth) {
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (depth <= 0) {
406d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    CFuncDoTrace(0);
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return 0;
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  } else {
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return CFunc(depth - 1) + 1;
410a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
4146ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// This test verifies that stack tracing doesn't crash when called on
4156ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// pure native code. StackTracer only unrolls JS code, so we can't
4166ded16be15dd865a9b21ea304d5273c8be299c87Steve Block// get any meaningful info here.
417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(PureCStackTrace) {
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  TickSample sample;
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitTraceEnv(&sample);
420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  // Check that sampler doesn't crash
421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(10, CFunc(10));
422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTEST(JsEntrySp) {
426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  InitializeVM();
427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  v8::HandleScope scope;
428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(0, GetJsEntrySp());
429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CompileRun("a = 1; b = a + 1;");
430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(0, GetJsEntrySp());
431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CompileRun("js_entry_sp();");
432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(0, GetJsEntrySp());
433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CompileRun("js_entry_sp_level2();");
434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CHECK_EQ(0, GetJsEntrySp());
435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#endif  // ENABLE_LOGGING_AND_PROFILING
438