Index: test/cctest/test-log-stack-tracer.cc |
=================================================================== |
--- test/cctest/test-log-stack-tracer.cc (revision 5389) |
+++ test/cctest/test-log-stack-tracer.cc (working copy) |
@@ -1,5 +1,30 @@ |
-// Copyright 2006-2009 the V8 project authors. All rights reserved. |
+// Copyright 2010 the V8 project authors. All rights reserved. |
+// Redistribution and use in source and binary forms, with or without |
+// modification, are permitted provided that the following conditions are |
+// met: |
// |
+// * Redistributions of source code must retain the above copyright |
+// notice, this list of conditions and the following disclaimer. |
+// * Redistributions in binary form must reproduce the above |
+// copyright notice, this list of conditions and the following |
+// disclaimer in the documentation and/or other materials provided |
+// with the distribution. |
+// * Neither the name of Google Inc. nor the names of its |
+// contributors may be used to endorse or promote products derived |
+// from this software without specific prior written permission. |
+// |
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+// |
// Tests of profiler-related functions from log.h |
#ifdef ENABLE_LOGGING_AND_PROFILING |
@@ -107,11 +132,17 @@ |
Address TraceExtension::GetFP(const v8::Arguments& args) { |
- CHECK_EQ(1, args.Length()); |
- // CodeGenerator::GenerateGetFramePointer pushes EBP / RBP value |
- // on stack. In 64-bit mode we can't use Smi operations code because |
- // they check that value is within Smi bounds. |
+ // Convert frame pointer from encoding as smis in the arguments to a pointer. |
+ CHECK_EQ(2, args.Length()); // Ignore second argument on 32-bit platform. |
+#if defined(V8_HOST_ARCH_32_BIT) |
Address fp = *reinterpret_cast<Address*>(*args[0]); |
+#elif defined(V8_HOST_ARCH_64_BIT) |
+ int64_t low_bits = *reinterpret_cast<uint64_t*>(*args[0]) >> 32; |
+ int64_t high_bits = *reinterpret_cast<uint64_t*>(*args[1]); |
+ Address fp = reinterpret_cast<Address>(high_bits | low_bits); |
+#else |
+#error Host architecture is neither 32-bit nor 64-bit. |
+#endif |
printf("Trace: %p\n", fp); |
return fp; |
} |
@@ -210,51 +241,60 @@ |
} |
-namespace v8 { |
-namespace internal { |
+// This C++ function is called as a constructor, to grab the frame pointer |
+// from the calling function. When this function runs, the stack contains |
+// a C_Entry frame and a Construct frame above the calling function's frame. |
+static v8::Handle<Value> construct_call(const v8::Arguments& args) { |
+ i::StackFrameIterator frame_iterator; |
+ CHECK(frame_iterator.frame()->is_exit()); |
+ frame_iterator.Advance(); |
+ CHECK(frame_iterator.frame()->is_construct()); |
+ frame_iterator.Advance(); |
+ i::StackFrame* calling_frame = frame_iterator.frame(); |
+ CHECK(calling_frame->is_java_script()); |
-class CodeGeneratorPatcher { |
- public: |
- CodeGeneratorPatcher() { |
- CodeGenerator::InlineRuntimeLUT gen_get_frame_pointer = |
- {&CodeGenerator::GenerateGetFramePointer, "_GetFramePointer", 0}; |
- // _RandomHeapNumber is just used as a dummy function that has zero |
- // arguments, the same as the _GetFramePointer function we actually patch |
- // in. |
- bool result = CodeGenerator::PatchInlineRuntimeEntry( |
- NewString("_RandomHeapNumber"), |
- gen_get_frame_pointer, &old_inline_entry); |
- CHECK(result); |
- } |
+#if defined(V8_HOST_ARCH_32_BIT) |
+ int32_t low_bits = reinterpret_cast<intptr_t>(calling_frame->fp()); |
+ args.This()->Set(v8_str("low_bits"), v8_num(low_bits >> 1)); |
+#elif defined(V8_HOST_ARCH_64_BIT) |
+ int32_t low_bits = reinterpret_cast<uintptr_t>(calling_frame->fp()); |
+ int32_t high_bits = reinterpret_cast<uintptr_t>(calling_frame->fp()) >> 32; |
+ args.This()->Set(v8_str("low_bits"), v8_num(low_bits)); |
+ args.This()->Set(v8_str("high_bits"), v8_num(high_bits)); |
+#else |
+#error Host architecture is neither 32-bit nor 64-bit. |
+#endif |
+ return args.This(); |
+} |
- ~CodeGeneratorPatcher() { |
- CHECK(CodeGenerator::PatchInlineRuntimeEntry( |
- NewString("_GetFramePointer"), |
- old_inline_entry, NULL)); |
- } |
- private: |
- CodeGenerator::InlineRuntimeLUT old_inline_entry; |
-}; |
+// Use the API to create a JSFunction object that calls the above C++ function. |
+void CreateFramePointerGrabberConstructor(const char* constructor_name) { |
+ Local<v8::FunctionTemplate> constructor_template = |
+ v8::FunctionTemplate::New(construct_call); |
+ constructor_template->SetClassName(v8_str("FPGrabber")); |
+ Local<Function> fun = constructor_template->GetFunction(); |
+ env->Global()->Set(v8_str(constructor_name), fun); |
+} |
-} } // namespace v8::internal |
- |
// Creates a global function named 'func_name' that calls the tracing |
// function 'trace_func_name' with an actual EBP register value, |
-// shifted right to be presented as Smi. |
+// encoded as one or two Smis. |
static void CreateTraceCallerFunction(const char* func_name, |
const char* trace_func_name) { |
i::EmbeddedVector<char, 256> trace_call_buf; |
- i::OS::SNPrintF(trace_call_buf, "%s(%%_GetFramePointer());", trace_func_name); |
+ i::OS::SNPrintF(trace_call_buf, |
+ "fp = new FPGrabber(); %s(fp.low_bits, fp.high_bits);", |
+ trace_func_name); |
+ // Create the FPGrabber function, which grabs the caller's frame pointer |
+ // when called as a constructor. |
+ CreateFramePointerGrabberConstructor("FPGrabber"); |
+ |
// Compile the script. |
- i::CodeGeneratorPatcher patcher; |
- bool allow_natives_syntax = i::FLAG_allow_natives_syntax; |
- i::FLAG_allow_natives_syntax = true; |
Handle<JSFunction> func = CompileFunction(trace_call_buf.start()); |
CHECK(!func.is_null()); |
- i::FLAG_allow_natives_syntax = allow_natives_syntax; |
func->shared()->set_name(*NewString(func_name)); |
#ifdef DEBUG |
@@ -273,12 +313,6 @@ |
// StackTracer uses Top::c_entry_fp as a starting point for stack |
// walking. |
TEST(CFromJSStackTrace) { |
- // TODO(711): The hack of replacing the inline runtime function |
- // RandomHeapNumber with GetFrameNumber does not work with the way |
- // the full compiler generates inline runtime calls. |
- i::FLAG_full_compiler = false; |
- i::FLAG_always_full_compiler = false; |
- |
TickSample sample; |
InitTraceEnv(&sample); |
@@ -314,12 +348,6 @@ |
// Top::c_entry_fp value. In this case, StackTracer uses passed frame |
// pointer value as a starting point for stack walking. |
TEST(PureJSStackTrace) { |
- // TODO(711): The hack of replacing the inline runtime function |
- // RandomHeapNumber with GetFrameNumber does not work with the way |
- // the full compiler generates inline runtime calls. |
- i::FLAG_full_compiler = false; |
- i::FLAG_always_full_compiler = false; |
- |
TickSample sample; |
InitTraceEnv(&sample); |