Author: [email protected]
Date: Thu May  7 02:24:43 2009
New Revision: 1892

Modified:
    branches/bleeding_edge/src/arm/codegen-arm.h
    branches/bleeding_edge/src/codegen.cc
    branches/bleeding_edge/src/codegen.h
    branches/bleeding_edge/src/ia32/codegen-ia32.cc
    branches/bleeding_edge/src/ia32/codegen-ia32.h
    branches/bleeding_edge/test/cctest/test-log-ia32.cc

Log:
Restore stack backtrace tests removed in revision 1785.

To re-enable tests, instead of compiled code patching, inlined code is used.
Inlined code is only installed in test.

Review URL: http://codereview.chromium.org/108015

Modified: branches/bleeding_edge/src/arm/codegen-arm.h
==============================================================================
--- branches/bleeding_edge/src/arm/codegen-arm.h        (original)
+++ branches/bleeding_edge/src/arm/codegen-arm.h        Thu May  7 02:24:43 2009
@@ -303,7 +303,17 @@
    void Branch(bool if_true, JumpTarget* target);
    void CheckStack();

+  struct InlineRuntimeLUT {
+    void (CodeGenerator::*method)(ZoneList<Expression*>*);
+    const char* name;
+  };
+
+  static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
    bool CheckForInlineRuntimeCall(CallRuntime* node);
+  static bool PatchInlineRuntimeEntry(Handle<String> name,
+                                      const InlineRuntimeLUT& new_entry,
+                                      InlineRuntimeLUT* old_entry);
+
    Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
    void ProcessDeclarations(ZoneList<Declaration*>* declarations);

@@ -432,6 +442,8 @@
    // called from spilled code, because they do not leave the virtual frame
    // in a spilled state.
    bool in_spilled_code_;
+
+  static InlineRuntimeLUT kInlineRuntimeLUT[];

    friend class VirtualFrame;
    friend class JumpTarget;

Modified: branches/bleeding_edge/src/codegen.cc
==============================================================================
--- branches/bleeding_edge/src/codegen.cc       (original)
+++ branches/bleeding_edge/src/codegen.cc       Thu May  7 02:24:43 2009
@@ -386,54 +386,66 @@
  }


-struct InlineRuntimeLUT {
-  void (CodeGenerator::*method)(ZoneList<Expression*>*);
-  const char* name;
+
+// Special cases: These 'runtime calls' manipulate the current
+// frame and are only used 1 or two places, so we generate them
+// inline instead of generating calls to them.  They are used
+// for implementing Function.prototype.call() and
+// Function.prototype.apply().
+CodeGenerator::InlineRuntimeLUT CodeGenerator::kInlineRuntimeLUT[] = {
+  {&CodeGenerator::GenerateIsSmi, "_IsSmi"},
+  {&CodeGenerator::GenerateIsNonNegativeSmi, "_IsNonNegativeSmi"},
+  {&CodeGenerator::GenerateIsArray, "_IsArray"},
+  {&CodeGenerator::GenerateArgumentsLength, "_ArgumentsLength"},
+  {&CodeGenerator::GenerateArgumentsAccess, "_Arguments"},
+  {&CodeGenerator::GenerateValueOf, "_ValueOf"},
+  {&CodeGenerator::GenerateSetValueOf, "_SetValueOf"},
+  {&CodeGenerator::GenerateFastCharCodeAt, "_FastCharCodeAt"},
+  {&CodeGenerator::GenerateObjectEquals, "_ObjectEquals"},
+  {&CodeGenerator::GenerateLog, "_Log"}
  };


+CodeGenerator::InlineRuntimeLUT* CodeGenerator::FindInlineRuntimeLUT(
+    Handle<String> name) {
+  const int entries_count =
+      sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
+  for (int i = 0; i < entries_count; i++) {
+    InlineRuntimeLUT* entry = &kInlineRuntimeLUT[i];
+    if (name->IsEqualTo(CStrVector(entry->name))) {
+      return entry;
+    }
+  }
+  return NULL;
+}
+
+
  bool CodeGenerator::CheckForInlineRuntimeCall(CallRuntime* node) {
    ZoneList<Expression*>* args = node->arguments();
-  // Special cases: These 'runtime calls' manipulate the current
-  // frame and are only used 1 or two places, so we generate them
-  // inline instead of generating calls to them.  They are used
-  // for implementing Function.prototype.call() and
-  // Function.prototype.apply().
-  static const InlineRuntimeLUT kInlineRuntimeLUT[] = {
-    {&v8::internal::CodeGenerator::GenerateIsSmi,
-     "_IsSmi"},
-    {&v8::internal::CodeGenerator::GenerateIsNonNegativeSmi,
-     "_IsNonNegativeSmi"},
-    {&v8::internal::CodeGenerator::GenerateIsArray,
-     "_IsArray"},
-    {&v8::internal::CodeGenerator::GenerateArgumentsLength,
-     "_ArgumentsLength"},
-    {&v8::internal::CodeGenerator::GenerateArgumentsAccess,
-     "_Arguments"},
-    {&v8::internal::CodeGenerator::GenerateValueOf,
-     "_ValueOf"},
-    {&v8::internal::CodeGenerator::GenerateSetValueOf,
-     "_SetValueOf"},
-    {&v8::internal::CodeGenerator::GenerateFastCharCodeAt,
-     "_FastCharCodeAt"},
-    {&v8::internal::CodeGenerator::GenerateObjectEquals,
-     "_ObjectEquals"},
-    {&v8::internal::CodeGenerator::GenerateLog,
-     "_Log"}
-  };
    Handle<String> name = node->name();
    if (name->length() > 0 && name->Get(0) == '_') {
-    for (unsigned i = 0;
-         i < sizeof(kInlineRuntimeLUT) / sizeof(InlineRuntimeLUT);
-         i++) {
-      const InlineRuntimeLUT* entry = kInlineRuntimeLUT + i;
-      if (name->IsEqualTo(CStrVector(entry->name))) {
-        ((*this).*(entry->method))(args);
-        return true;
-      }
+    InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
+    if (entry != NULL) {
+      ((*this).*(entry->method))(args);
+      return true;
      }
    }
    return false;
+}
+
+
+bool CodeGenerator::PatchInlineRuntimeEntry(Handle<String> name,
+    const CodeGenerator::InlineRuntimeLUT& new_entry,
+    CodeGenerator::InlineRuntimeLUT* old_entry) {
+  InlineRuntimeLUT* entry = FindInlineRuntimeLUT(name);
+  if (entry == NULL) return false;
+  if (old_entry != NULL) {
+    old_entry->name = entry->name;
+    old_entry->method = entry->method;
+  }
+  entry->name = new_entry.name;
+  entry->method = new_entry.method;
+  return true;
  }



Modified: branches/bleeding_edge/src/codegen.h
==============================================================================
--- branches/bleeding_edge/src/codegen.h        (original)
+++ branches/bleeding_edge/src/codegen.h        Thu May  7 02:24:43 2009
@@ -59,7 +59,9 @@
  //   ComputeCallInitializeInLoop
  //   ProcessDeclarations
  //   DeclareGlobals
+//   FindInlineRuntimeLUT
  //   CheckForInlineRuntimeCall
+//   PatchInlineRuntimeEntry
  //   GenerateFastCaseSwitchStatement
  //   GenerateFastCaseSwitchCases
  //   TryGenerateFastCaseSwitchStatement

Modified: branches/bleeding_edge/src/ia32/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/ia32/codegen-ia32.cc     (original)
+++ branches/bleeding_edge/src/ia32/codegen-ia32.cc     Thu May  7 02:24:43 2009
@@ -4544,6 +4544,17 @@
  }


+void CodeGenerator::GenerateGetFramePointer(ZoneList<Expression*>* args) {
+  ASSERT(args->length() == 0);
+  ASSERT(kSmiTagSize == 1 && kSmiTag == 0);  // shifting code depends on  
this
+  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);
+}
+
+
  void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
    if (CheckForInlineRuntimeCall(node)) {
      return;

Modified: branches/bleeding_edge/src/ia32/codegen-ia32.h
==============================================================================
--- branches/bleeding_edge/src/ia32/codegen-ia32.h      (original)
+++ branches/bleeding_edge/src/ia32/codegen-ia32.h      Thu May  7 02:24:43 2009
@@ -473,7 +473,17 @@

    void CheckStack();

+  struct InlineRuntimeLUT {
+    void (CodeGenerator::*method)(ZoneList<Expression*>*);
+    const char* name;
+  };
+
+  static InlineRuntimeLUT* FindInlineRuntimeLUT(Handle<String> name);
    bool CheckForInlineRuntimeCall(CallRuntime* node);
+  static bool PatchInlineRuntimeEntry(Handle<String> name,
+                                      const InlineRuntimeLUT& new_entry,
+                                      InlineRuntimeLUT* old_entry);
+
    Handle<JSFunction> BuildBoilerplate(FunctionLiteral* node);
    void ProcessDeclarations(ZoneList<Declaration*>* declarations);

@@ -508,6 +518,7 @@

    void GenerateLog(ZoneList<Expression*>* args);

+  void GenerateGetFramePointer(ZoneList<Expression*>* args);

    // Methods and constants for fast case switch statement support.
    //
@@ -604,10 +615,14 @@
    // in a spilled state.
    bool in_spilled_code_;

+  static InlineRuntimeLUT kInlineRuntimeLUT[];
+
    friend class VirtualFrame;
    friend class JumpTarget;
    friend class Reference;
    friend class Result;
+
+  friend class CodeGeneratorPatcher;  // Used in test-log-ia32.cc

    DISALLOW_COPY_AND_ASSIGN(CodeGenerator);
  };

Modified: branches/bleeding_edge/test/cctest/test-log-ia32.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-log-ia32.cc (original)
+++ branches/bleeding_edge/test/cctest/test-log-ia32.cc Thu May  7 02:24:43  
2009
@@ -8,9 +8,11 @@

  #include "v8.h"

+#include "codegen.h"
  #include "log.h"
  #include "top.h"
  #include "cctest.h"
+#include "disassembler.h"

  using v8::Function;
  using v8::Local;
@@ -20,12 +22,15 @@
  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;

@@ -42,8 +47,8 @@
  }


-static void DoTrace(unsigned int fp) {
-  trace_env.sample->fp = fp;
+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;
@@ -53,7 +58,7 @@

  // Hide c_entry_fp to emulate situation when sampling is done while
  // pure JS code is being executed
-static void DoTraceHideCEntryFPAddress(unsigned int fp) {
+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;
@@ -62,6 +67,28 @@
  }


+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 {
@@ -72,7 +99,7 @@
    static v8::Handle<v8::Value> Trace(const v8::Arguments& args);
    static v8::Handle<v8::Value> JSTrace(const v8::Arguments& args);
   private:
-  static unsigned int GetFP(const v8::Arguments& args);
+  static Address GetFP(const v8::Arguments& args);
    static const char* kSource;
  };

@@ -95,10 +122,10 @@
  }


-unsigned int TraceExtension::GetFP(const v8::Arguments& args) {
+Address TraceExtension::GetFP(const v8::Arguments& args) {
    CHECK_EQ(1, args.Length());
-  unsigned int fp = args[0]->Int32Value() << 2;
-  printf("Trace: %08x\n", fp);
+  Address fp = reinterpret_cast<Address>(args[0]->Int32Value() << 2);
+  printf("Trace: %p\n", fp);
    return fp;
  }

@@ -119,10 +146,162 @@
  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 void CompileRun(const char* source) {
+  Script::Compile(String::New(source))->Run();
+}
+
+
+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;
+  StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
+  InitTraceEnv(&tracer, &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;
+  StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
+  InitTraceEnv(&tracer, &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() {
-  unsigned int fp;
+  Address fp;
  #ifdef __GNUC__
-  fp = reinterpret_cast<unsigned int>(__builtin_frame_address(0));
+  fp = reinterpret_cast<Address>(__builtin_frame_address(0));
  #elif defined _MSC_VER
    __asm mov [fp], ebp  // NOLINT
  #endif
@@ -142,7 +321,7 @@

  TEST(PureCStackTrace) {
    TickSample sample;
-  StackTracer tracer(reinterpret_cast<unsigned int>(&sample));
+  StackTracer tracer(reinterpret_cast<uintptr_t>(&sample));
    InitTraceEnv(&tracer, &sample);
    // Check that sampler doesn't crash
    CHECK_EQ(10, CFunc(10));

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to