Revision: 2597 Author: [email protected] Date: Fri Jul 31 04:07:05 2009 Log: X64: enable stack sampling in profiler.
Added necessary code to initialize Top::js_entry_sp value. Renamed 'test-log-ia32' test to 'test-log-stack-tracer' and enabled it in 64-bit version. Review URL: http://codereview.chromium.org/160446 http://code.google.com/p/v8/source/detail?r=2597 Added: /branches/bleeding_edge/test/cctest/test-log-stack-tracer.cc Deleted: /branches/bleeding_edge/test/cctest/test-log-ia32.cc Modified: /branches/bleeding_edge/src/ia32/codegen-ia32.cc /branches/bleeding_edge/src/ia32/codegen-ia32.h /branches/bleeding_edge/src/x64/codegen-x64.cc /branches/bleeding_edge/src/x64/codegen-x64.h /branches/bleeding_edge/test/cctest/SConscript /branches/bleeding_edge/tools/visual_studio/v8_cctest.vcproj ======================================= --- /dev/null +++ /branches/bleeding_edge/test/cctest/test-log-stack-tracer.cc Fri Jul 31 04:07:05 2009 @@ -0,0 +1,376 @@ +// Copyright 2006-2009 the V8 project authors. All rights reserved. +// +// Tests of profiler-related functions from log.h + +#ifdef ENABLE_LOGGING_AND_PROFILING + +#include <stdlib.h> + +#include "v8.h" + +#include "codegen.h" +#include "log.h" +#include "top.h" +#include "cctest.h" +#include "disassembler.h" +#include "register-allocator-inl.h" + +using v8::Function; +using v8::Local; +using v8::Object; +using v8::Script; +using v8::String; +using v8::Value; + +using v8::internal::byte; +using v8::internal::Address; +using v8::internal::Handle; +using v8::internal::JSFunction; +using v8::internal::StackTracer; +using v8::internal::TickSample; +using v8::internal::Top; + +namespace i = v8::internal; + + +static v8::Persistent<v8::Context> env; + + +static struct { + TickSample* sample; +} trace_env = { NULL }; + + +static void InitTraceEnv(TickSample* sample) { + trace_env.sample = sample; +} + + +static void DoTrace(Address fp) { + trace_env.sample->fp = reinterpret_cast<uintptr_t>(fp); + // sp is only used to define stack high bound + trace_env.sample->sp = + reinterpret_cast<uintptr_t>(trace_env.sample) - 10240; + StackTracer::Trace(trace_env.sample); +} + + +// Hide c_entry_fp to emulate situation when sampling is done while +// pure JS code is being executed +static void DoTraceHideCEntryFPAddress(Address fp) { + v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); + CHECK(saved_c_frame_fp); + *(Top::c_entry_fp_address()) = 0; + DoTrace(fp); + *(Top::c_entry_fp_address()) = saved_c_frame_fp; +} + + +static void CheckRetAddrIsInFunction(const char* func_name, + Address ret_addr, + Address func_start_addr, + unsigned int func_len) { + printf("CheckRetAddrIsInFunction \"%s\": %p %p %p\n", + func_name, func_start_addr, ret_addr, func_start_addr + func_len); + CHECK_GE(ret_addr, func_start_addr); + CHECK_GE(func_start_addr + func_len, ret_addr); +} + + +static void CheckRetAddrIsInJSFunction(const char* func_name, + Address ret_addr, + Handle<JSFunction> func) { + v8::internal::Code* func_code = func->code(); + CheckRetAddrIsInFunction( + func_name, ret_addr, + func_code->instruction_start(), + func_code->ExecutableSize()); +} + + +// --- T r a c e E x t e n s i o n --- + +class TraceExtension : public v8::Extension { + public: + TraceExtension() : v8::Extension("v8/trace", kSource) { } + virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( + v8::Handle<String> name); + static v8::Handle<v8::Value> Trace(const v8::Arguments& args); + static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args); + static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args); + static v8::Handle<v8::Value> JSEntrySPLevel2(const v8::Arguments& args); + private: + static Address GetFP(const v8::Arguments& args); + static const char* kSource; +}; + + +const char* TraceExtension::kSource = + "native function trace();" + "native function js_trace();" + "native function js_entry_sp();" + "native function js_entry_sp_level2();"; + +v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction( + v8::Handle<String> name) { + if (name->Equals(String::New("trace"))) { + return v8::FunctionTemplate::New(TraceExtension::Trace); + } else if (name->Equals(String::New("js_trace"))) { + return v8::FunctionTemplate::New(TraceExtension::JSTrace); + } else if (name->Equals(String::New("js_entry_sp"))) { + return v8::FunctionTemplate::New(TraceExtension::JSEntrySP); + } else if (name->Equals(String::New("js_entry_sp_level2"))) { + return v8::FunctionTemplate::New(TraceExtension::JSEntrySPLevel2); + } else { + CHECK(false); + return v8::Handle<v8::FunctionTemplate>(); + } +} + + +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. + Address fp = *reinterpret_cast<Address*>(*args[0]); + printf("Trace: %p\n", fp); + return fp; +} + + +v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) { + DoTrace(GetFP(args)); + return v8::Undefined(); +} + + +v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { + DoTraceHideCEntryFPAddress(GetFP(args)); + return v8::Undefined(); +} + + +static Address GetJsEntrySp() { + CHECK_NE(NULL, Top::GetCurrentThread()); + return Top::js_entry_sp(Top::GetCurrentThread()); +} + + +v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) { + CHECK_NE(0, GetJsEntrySp()); + return v8::Undefined(); +} + + +static void CompileRun(const char* source) { + Script::Compile(String::New(source))->Run(); +} + + +v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2( + const v8::Arguments& args) { + v8::HandleScope scope; + const Address js_entry_sp = GetJsEntrySp(); + CHECK_NE(0, js_entry_sp); + CompileRun("js_entry_sp();"); + CHECK_EQ(js_entry_sp, GetJsEntrySp()); + return v8::Undefined(); +} + + +static TraceExtension kTraceExtension; +v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension); + + +static void InitializeVM() { + if (env.IsEmpty()) { + v8::HandleScope scope; + const char* extensions[] = { "v8/trace" }; + v8::ExtensionConfiguration config(1, extensions); + env = v8::Context::New(&config); + } + v8::HandleScope scope; + env->Enter(); +} + + +static Handle<JSFunction> CompileFunction(const char* source) { + return v8::Utils::OpenHandle(*Script::Compile(String::New(source))); +} + + +static Local<Value> GetGlobalProperty(const char* name) { + return env->Global()->Get(String::New(name)); +} + + +static Handle<JSFunction> GetGlobalJSFunction(const char* name) { + Handle<JSFunction> js_func(JSFunction::cast( + *(v8::Utils::OpenHandle( + *GetGlobalProperty(name))))); + return js_func; +} + + +static void CheckRetAddrIsInJSFunction(const char* func_name, + Address ret_addr) { + CheckRetAddrIsInJSFunction(func_name, ret_addr, + GetGlobalJSFunction(func_name)); +} + + +static void SetGlobalProperty(const char* name, Local<Value> value) { + env->Global()->Set(String::New(name), value); +} + + +static Handle<v8::internal::String> NewString(const char* s) { + return i::Factory::NewStringFromAscii(i::CStrVector(s)); +} + + +namespace v8 { +namespace internal { + +class CodeGeneratorPatcher { + public: + CodeGeneratorPatcher() { + CodeGenerator::InlineRuntimeLUT genGetFramePointer = + {&CodeGenerator::GenerateGetFramePointer, "_GetFramePointer"}; + // _FastCharCodeAt is not used in our tests. + bool result = CodeGenerator::PatchInlineRuntimeEntry( + NewString("_FastCharCodeAt"), + genGetFramePointer, &oldInlineEntry); + CHECK(result); + } + + ~CodeGeneratorPatcher() { + CHECK(CodeGenerator::PatchInlineRuntimeEntry( + NewString("_GetFramePointer"), + oldInlineEntry, NULL)); + } + + private: + CodeGenerator::InlineRuntimeLUT oldInlineEntry; +}; + +} } // 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. +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); + + // 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; + +#ifdef DEBUG + v8::internal::Code* func_code = func->code(); + CHECK(func_code->IsCode()); + func_code->Print(); +#endif + + SetGlobalProperty(func_name, v8::ToApi<Value>(func)); +} + + +TEST(CFromJSStackTrace) { + TickSample sample; + InitTraceEnv(&sample); + + InitializeVM(); + v8::HandleScope scope; + CreateTraceCallerFunction("JSFuncDoTrace", "trace"); + CompileRun( + "function JSTrace() {" + " JSFuncDoTrace();" + "};\n" + "JSTrace();"); + CHECK_GT(sample.frames_count, 1); + // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace" + CheckRetAddrIsInJSFunction("JSFuncDoTrace", + sample.stack[0]); + CheckRetAddrIsInJSFunction("JSTrace", + sample.stack[1]); +} + + +TEST(PureJSStackTrace) { + TickSample sample; + InitTraceEnv(&sample); + + InitializeVM(); + v8::HandleScope scope; + CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); + CompileRun( + "function JSTrace() {" + " JSFuncDoTrace();" + "};\n" + "function OuterJSTrace() {" + " JSTrace();" + "};\n" + "OuterJSTrace();"); + CHECK_GT(sample.frames_count, 1); + // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" + CheckRetAddrIsInJSFunction("JSTrace", + sample.stack[0]); + CheckRetAddrIsInJSFunction("OuterJSTrace", + sample.stack[1]); +} + + +static void CFuncDoTrace() { + Address fp; +#ifdef __GNUC__ + fp = reinterpret_cast<Address>(__builtin_frame_address(0)); +#elif defined _MSC_VER && defined V8_TARGET_ARCH_IA32 + __asm mov [fp], ebp // NOLINT +#elif defined _MSC_VER && defined V8_TARGET_ARCH_X64 + // FIXME: I haven't really tried to compile it. + __asm movq [fp], rbp // NOLINT +#endif + DoTrace(fp); +} + + +static int CFunc(int depth) { + if (depth <= 0) { + CFuncDoTrace(); + return 0; + } else { + return CFunc(depth - 1) + 1; + } +} + + +TEST(PureCStackTrace) { + TickSample sample; + InitTraceEnv(&sample); + // Check that sampler doesn't crash + CHECK_EQ(10, CFunc(10)); +} + + +TEST(JsEntrySp) { + InitializeVM(); + v8::HandleScope scope; + CHECK_EQ(0, GetJsEntrySp()); + CompileRun("a = 1; b = a + 1;"); + CHECK_EQ(0, GetJsEntrySp()); + CompileRun("js_entry_sp();"); + CHECK_EQ(0, GetJsEntrySp()); + CompileRun("js_entry_sp_level2();"); + CHECK_EQ(0, GetJsEntrySp()); +} + +#endif // ENABLE_LOGGING_AND_PROFILING ======================================= --- /branches/bleeding_edge/test/cctest/test-log-ia32.cc Tue Jun 2 02:33:17 2009 +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2006-2009 the V8 project authors. All rights reserved. -// -// Tests of profiler-related functions from log.h - -#ifdef ENABLE_LOGGING_AND_PROFILING - -#include <stdlib.h> - -#include "v8.h" - -#include "codegen.h" -#include "log.h" -#include "top.h" -#include "cctest.h" -#include "disassembler.h" -#include "register-allocator-inl.h" - -using v8::Function; -using v8::Local; -using v8::Object; -using v8::Script; -using v8::String; -using v8::Value; - -using v8::internal::byte; -using v8::internal::Address; -using v8::internal::Handle; -using v8::internal::JSFunction; -using v8::internal::StackTracer; -using v8::internal::TickSample; -using v8::internal::Top; - -namespace i = v8::internal; - - -static v8::Persistent<v8::Context> env; - - -static struct { - TickSample* sample; -} trace_env = { NULL }; - - -static void InitTraceEnv(TickSample* sample) { - trace_env.sample = sample; -} - - -static void DoTrace(Address fp) { - trace_env.sample->fp = reinterpret_cast<uintptr_t>(fp); - // sp is only used to define stack high bound - trace_env.sample->sp = - reinterpret_cast<unsigned int>(trace_env.sample) - 10240; - StackTracer::Trace(trace_env.sample); -} - - -// Hide c_entry_fp to emulate situation when sampling is done while -// pure JS code is being executed -static void DoTraceHideCEntryFPAddress(Address fp) { - v8::internal::Address saved_c_frame_fp = *(Top::c_entry_fp_address()); - CHECK(saved_c_frame_fp); - *(Top::c_entry_fp_address()) = 0; - DoTrace(fp); - *(Top::c_entry_fp_address()) = saved_c_frame_fp; -} - - -static void CheckRetAddrIsInFunction(const char* func_name, - Address ret_addr, - Address func_start_addr, - unsigned int func_len) { - printf("CheckRetAddrIsInFunction \"%s\": %p %p %p\n", - func_name, func_start_addr, ret_addr, func_start_addr + func_len); - CHECK_GE(ret_addr, func_start_addr); - CHECK_GE(func_start_addr + func_len, ret_addr); -} - - -static void CheckRetAddrIsInJSFunction(const char* func_name, - Address ret_addr, - Handle<JSFunction> func) { - v8::internal::Code* func_code = func->code(); - CheckRetAddrIsInFunction( - func_name, ret_addr, - func_code->instruction_start(), - func_code->ExecutableSize()); -} - - -// --- T r a c e E x t e n s i o n --- - -class TraceExtension : public v8::Extension { - public: - TraceExtension() : v8::Extension("v8/trace", kSource) { } - virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( - v8::Handle<String> name); - static v8::Handle<v8::Value> Trace(const v8::Arguments& args); - static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args); - static v8::Handle<v8::Value> JSEntrySP(const v8::Arguments& args); - static v8::Handle<v8::Value> JSEntrySPLevel2(const v8::Arguments& args); - private: - static Address GetFP(const v8::Arguments& args); - static const char* kSource; -}; - - -const char* TraceExtension::kSource = - "native function trace();" - "native function js_trace();" - "native function js_entry_sp();" - "native function js_entry_sp_level2();"; - -v8::Handle<v8::FunctionTemplate> TraceExtension::GetNativeFunction( - v8::Handle<String> name) { - if (name->Equals(String::New("trace"))) { - return v8::FunctionTemplate::New(TraceExtension::Trace); - } else if (name->Equals(String::New("js_trace"))) { - return v8::FunctionTemplate::New(TraceExtension::JSTrace); - } else if (name->Equals(String::New("js_entry_sp"))) { - return v8::FunctionTemplate::New(TraceExtension::JSEntrySP); - } else if (name->Equals(String::New("js_entry_sp_level2"))) { - return v8::FunctionTemplate::New(TraceExtension::JSEntrySPLevel2); - } else { - CHECK(false); - return v8::Handle<v8::FunctionTemplate>(); - } -} - - -Address TraceExtension::GetFP(const v8::Arguments& args) { - CHECK_EQ(1, args.Length()); - Address fp = reinterpret_cast<Address>(args[0]->Int32Value() << 2); - printf("Trace: %p\n", fp); - return fp; -} - - -v8::Handle<v8::Value> TraceExtension::Trace(const v8::Arguments& args) { - DoTrace(GetFP(args)); - return v8::Undefined(); -} - - -v8::Handle<v8::Value> TraceExtension::JSTrace(const v8::Arguments& args) { - DoTraceHideCEntryFPAddress(GetFP(args)); - return v8::Undefined(); -} - - -static Address GetJsEntrySp() { - CHECK_NE(NULL, Top::GetCurrentThread()); - return Top::js_entry_sp(Top::GetCurrentThread()); -} - - -v8::Handle<v8::Value> TraceExtension::JSEntrySP(const v8::Arguments& args) { - CHECK_NE(0, GetJsEntrySp()); - return v8::Undefined(); -} - - -static void CompileRun(const char* source) { - Script::Compile(String::New(source))->Run(); -} - - -v8::Handle<v8::Value> TraceExtension::JSEntrySPLevel2( - const v8::Arguments& args) { - v8::HandleScope scope; - const Address js_entry_sp = GetJsEntrySp(); - CHECK_NE(0, js_entry_sp); - CompileRun("js_entry_sp();"); - CHECK_EQ(js_entry_sp, GetJsEntrySp()); - return v8::Undefined(); -} - - -static TraceExtension kTraceExtension; -v8::DeclareExtension kTraceExtensionDeclaration(&kTraceExtension); - - -static void InitializeVM() { - if (env.IsEmpty()) { - v8::HandleScope scope; - const char* extensions[] = { "v8/trace" }; - v8::ExtensionConfiguration config(1, extensions); - env = v8::Context::New(&config); - } - v8::HandleScope scope; - env->Enter(); -} - - -static Handle<JSFunction> CompileFunction(const char* source) { - return v8::Utils::OpenHandle(*Script::Compile(String::New(source))); -} - - -static Local<Value> GetGlobalProperty(const char* name) { - return env->Global()->Get(String::New(name)); -} - - -static Handle<JSFunction> GetGlobalJSFunction(const char* name) { - Handle<JSFunction> js_func(JSFunction::cast( - *(v8::Utils::OpenHandle( - *GetGlobalProperty(name))))); - return js_func; -} - - -static void CheckRetAddrIsInJSFunction(const char* func_name, - Address ret_addr) { - CheckRetAddrIsInJSFunction(func_name, ret_addr, - GetGlobalJSFunction(func_name)); -} - - -static void SetGlobalProperty(const char* name, Local<Value> value) { - env->Global()->Set(String::New(name), value); -} - - -static Handle<v8::internal::String> NewString(const char* s) { - return i::Factory::NewStringFromAscii(i::CStrVector(s)); -} - - -namespace v8 { -namespace internal { - -class CodeGeneratorPatcher { - public: - CodeGeneratorPatcher() { - CodeGenerator::InlineRuntimeLUT genGetFramePointer = - {&CodeGenerator::GenerateGetFramePointer, "_GetFramePointer"}; - // _FastCharCodeAt is not used in our tests. - bool result = CodeGenerator::PatchInlineRuntimeEntry( - NewString("_FastCharCodeAt"), - genGetFramePointer, &oldInlineEntry); - CHECK(result); - } - - ~CodeGeneratorPatcher() { - CHECK(CodeGenerator::PatchInlineRuntimeEntry( - NewString("_GetFramePointer"), - oldInlineEntry, NULL)); - } - - private: - CodeGenerator::InlineRuntimeLUT oldInlineEntry; -}; - -} } // 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. -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); - - // 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; - -#ifdef DEBUG - v8::internal::Code* func_code = func->code(); - CHECK(func_code->IsCode()); - func_code->Print(); -#endif - - SetGlobalProperty(func_name, v8::ToApi<Value>(func)); -} - - -TEST(CFromJSStackTrace) { - TickSample sample; - InitTraceEnv(&sample); - - InitializeVM(); - v8::HandleScope scope; - CreateTraceCallerFunction("JSFuncDoTrace", "trace"); - CompileRun( - "function JSTrace() {" - " JSFuncDoTrace();" - "};\n" - "JSTrace();"); - CHECK_GT(sample.frames_count, 1); - // Stack sampling will start from the first JS function, i.e. "JSFuncDoTrace" - CheckRetAddrIsInJSFunction("JSFuncDoTrace", - sample.stack[0]); - CheckRetAddrIsInJSFunction("JSTrace", - sample.stack[1]); -} - - -TEST(PureJSStackTrace) { - TickSample sample; - InitTraceEnv(&sample); - - InitializeVM(); - v8::HandleScope scope; - CreateTraceCallerFunction("JSFuncDoTrace", "js_trace"); - CompileRun( - "function JSTrace() {" - " JSFuncDoTrace();" - "};\n" - "function OuterJSTrace() {" - " JSTrace();" - "};\n" - "OuterJSTrace();"); - CHECK_GT(sample.frames_count, 1); - // Stack sampling will start from the caller of JSFuncDoTrace, i.e. "JSTrace" - CheckRetAddrIsInJSFunction("JSTrace", - sample.stack[0]); - CheckRetAddrIsInJSFunction("OuterJSTrace", - sample.stack[1]); -} - - -static void CFuncDoTrace() { - Address fp; -#ifdef __GNUC__ - fp = reinterpret_cast<Address>(__builtin_frame_address(0)); -#elif defined _MSC_VER - __asm mov [fp], ebp // NOLINT -#endif - DoTrace(fp); -} - - -static int CFunc(int depth) { - if (depth <= 0) { - CFuncDoTrace(); - return 0; - } else { - return CFunc(depth - 1) + 1; - } -} - - -TEST(PureCStackTrace) { - TickSample sample; - InitTraceEnv(&sample); - // Check that sampler doesn't crash - CHECK_EQ(10, CFunc(10)); -} - - -TEST(JsEntrySp) { - InitializeVM(); - v8::HandleScope scope; - CHECK_EQ(0, GetJsEntrySp()); - CompileRun("a = 1; b = a + 1;"); - CHECK_EQ(0, GetJsEntrySp()); - CompileRun("js_entry_sp();"); - CHECK_EQ(0, GetJsEntrySp()); - CompileRun("js_entry_sp_level2();"); - CHECK_EQ(0, GetJsEntrySp()); -} - -#endif // ENABLE_LOGGING_AND_PROFILING ======================================= --- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Tue Jul 28 01:43:51 2009 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Fri Jul 31 04:07:05 2009 @@ -5154,11 +5154,10 @@ void CodeGenerator::GenerateGetFramePointer(ZoneList<Expression*>* args) { ASSERT(args->length() == 0); - ASSERT(kSmiTagSize == 1 && kSmiTag == 0); // shifting code depends on this + ASSERT(kSmiTag == 0); // EBP value is aligned, so it should look like Smi. Result ebp_as_smi = allocator_->Allocate(); ASSERT(ebp_as_smi.is_valid()); __ mov(ebp_as_smi.reg(), Operand(ebp)); - __ shr(ebp_as_smi.reg(), kSmiTagSize); frame_->Push(&ebp_as_smi); } @@ -7786,7 +7785,7 @@ // If this is the outermost JS call, set js_entry_sp value. ExternalReference js_entry_sp(Top::k_js_entry_sp_address); __ cmp(Operand::StaticVariable(js_entry_sp), Immediate(0)); - __ j(NegateCondition(equal), ¬_outermost_js); + __ j(not_equal, ¬_outermost_js); __ mov(Operand::StaticVariable(js_entry_sp), ebp); __ bind(¬_outermost_js); #endif @@ -7837,7 +7836,7 @@ // If current EBP value is the same as js_entry_sp value, it means that // the current function is the outermost. __ cmp(ebp, Operand::StaticVariable(js_entry_sp)); - __ j(NegateCondition(equal), ¬_outermost_js_2); + __ j(not_equal, ¬_outermost_js_2); __ mov(Operand::StaticVariable(js_entry_sp), Immediate(0)); __ bind(¬_outermost_js_2); #endif ======================================= --- /branches/bleeding_edge/src/ia32/codegen-ia32.h Thu Jul 30 05:09:05 2009 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.h Fri Jul 31 04:07:05 2009 @@ -603,7 +603,7 @@ friend class Reference; friend class Result; - friend class CodeGeneratorPatcher; // Used in test-log-ia32.cc + friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc DISALLOW_COPY_AND_ASSIGN(CodeGenerator); }; ======================================= --- /branches/bleeding_edge/src/x64/codegen-x64.cc Fri Jul 31 01:04:41 2009 +++ /branches/bleeding_edge/src/x64/codegen-x64.cc Fri Jul 31 04:07:05 2009 @@ -3419,6 +3419,16 @@ left.Unuse(); destination()->Split(equal); } + + +void CodeGenerator::GenerateGetFramePointer(ZoneList<Expression*>* args) { + ASSERT(args->length() == 0); + ASSERT(kSmiTag == 0); // RBP value is aligned, so it should look like Smi. + Result rbp_as_smi = allocator_->Allocate(); + ASSERT(rbp_as_smi.is_valid()); + __ movq(rbp_as_smi.reg(), rbp); + frame_->Push(&rbp_as_smi); +} void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) { @@ -6573,6 +6583,9 @@ void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { Label invoke, exit; +#ifdef ENABLE_LOGGING_AND_PROFILING + Label not_outermost_js, not_outermost_js_2; +#endif // Setup frame. __ push(rbp); @@ -6598,6 +6611,17 @@ __ load_rax(c_entry_fp); __ push(rax); +#ifdef ENABLE_LOGGING_AND_PROFILING + // If this is the outermost JS call, set js_entry_sp value. + ExternalReference js_entry_sp(Top::k_js_entry_sp_address); + __ load_rax(js_entry_sp); + __ testq(rax, rax); + __ j(not_zero, ¬_outermost_js); + __ movq(rax, rbp); + __ store_rax(js_entry_sp); + __ bind(¬_outermost_js); +#endif + // Call a faked try-block that does the invoke. __ call(&invoke); @@ -6640,6 +6664,16 @@ // Pop next_sp. __ addq(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); +#ifdef ENABLE_LOGGING_AND_PROFILING + // If current EBP value is the same as js_entry_sp value, it means that + // the current function is the outermost. + __ movq(kScratchRegister, js_entry_sp); + __ cmpq(rbp, Operand(kScratchRegister, 0)); + __ j(not_equal, ¬_outermost_js_2); + __ movq(Operand(kScratchRegister, 0), Immediate(0)); + __ bind(¬_outermost_js_2); +#endif + // Restore the top frame descriptor from the stack. __ bind(&exit); __ movq(kScratchRegister, ExternalReference(Top::k_c_entry_fp_address)); ======================================= --- /branches/bleeding_edge/src/x64/codegen-x64.h Thu Jul 30 04:53:29 2009 +++ /branches/bleeding_edge/src/x64/codegen-x64.h Fri Jul 31 04:07:05 2009 @@ -534,6 +534,8 @@ void GenerateLog(ZoneList<Expression*>* args); + void GenerateGetFramePointer(ZoneList<Expression*>* args); + // Fast support for Math.random(). void GenerateRandomPositiveSmi(ZoneList<Expression*>* args); @@ -593,6 +595,8 @@ friend class Reference; friend class Result; + friend class CodeGeneratorPatcher; // Used in test-log-stack-tracer.cc + DISALLOW_COPY_AND_ASSIGN(CodeGenerator); }; ======================================= --- /branches/bleeding_edge/test/cctest/SConscript Thu May 28 00:08:09 2009 +++ /branches/bleeding_edge/test/cctest/SConscript Fri Jul 31 04:07:05 2009 @@ -63,9 +63,9 @@ 'arch:ia32': [ 'test-assembler-ia32.cc', 'test-disasm-ia32.cc', - 'test-log-ia32.cc' + 'test-log-stack-tracer.cc' ], - 'arch:x64': ['test-assembler-x64.cc'], + 'arch:x64': ['test-assembler-x64.cc', 'test-log-stack-tracer.cc'], 'os:linux': ['test-platform-linux.cc'], 'os:macos': ['test-platform-macos.cc'], 'os:nullos': ['test-platform-nullos.cc'], ======================================= --- /branches/bleeding_edge/tools/visual_studio/v8_cctest.vcproj Thu May 28 00:08:09 2009 +++ /branches/bleeding_edge/tools/visual_studio/v8_cctest.vcproj Fri Jul 31 04:07:05 2009 @@ -210,7 +210,7 @@ > </File> <File - RelativePath="..\..\test\cctest\test-log-ia32.cc" + RelativePath="..\..\test\cctest\test-log-stack-tracer.cc" > </File> <File --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---
