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