Notify CPU profiler when calling native getters
authoryurys@chromium.org <yurys@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 13 Jun 2013 13:46:33 +0000 (13:46 +0000)
committeryurys@chromium.org <yurys@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 13 Jun 2013 13:46:33 +0000 (13:46 +0000)
This change modifies code produced by BaseLoadStubCompiler::GenerateLoadCallback so that instead of calling AccessorGetter direcly it calls InvokeAccessorGetter which changes VM state and calls the actual callback. This way CPU profiler knows which external callback is being executed in this case.

BUG=244580
R=dcarney@chromium.org, loislo@chromium.org, svenpanne@chromium.org

Review URL: https://codereview.chromium.org/16286016

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15116 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

25 files changed:
src/api.cc
src/api.h
src/arm/code-stubs-arm.cc
src/arm/code-stubs-arm.h
src/arm/macro-assembler-arm.cc
src/arm/macro-assembler-arm.h
src/arm/simulator-arm.cc
src/arm/stub-cache-arm.cc
src/assembler.h
src/cpu-profiler.h
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/ia32/stub-cache-ia32.cc
src/mips/code-stubs-mips.cc
src/mips/code-stubs-mips.h
src/mips/macro-assembler-mips.cc
src/mips/macro-assembler-mips.h
src/mips/simulator-mips.cc
src/mips/stub-cache-mips.cc
src/sampler.cc
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h
src/x64/stub-cache-x64.cc
test/cctest/test-api.cc
test/cctest/test-cpu-profiler.cc

index a7e0b2878fdd323b371122d626d87f4ca1dd8f8e..9b1d01cd8f4ead1bab6e46f03c3ed362157f8c13 100644 (file)
@@ -8005,4 +8005,55 @@ void DeferredHandles::Iterate(ObjectVisitor* v) {
 }
 
 
+v8::Handle<v8::Value> InvokeAccessorGetter(
+    v8::Local<v8::String> property,
+    const v8::AccessorInfo& info,
+    v8::AccessorGetter getter) {
+  Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate());
+  Address getter_address = reinterpret_cast<Address>(reinterpret_cast<intptr_t>(
+      getter));
+  // Leaving JavaScript.
+  VMState<EXTERNAL> state(isolate);
+  ExternalCallbackScope call_scope(isolate, getter_address);
+  return getter(property, info);
+}
+
+
+void InvokeAccessorGetterCallback(
+    v8::Local<v8::String> property,
+    const v8::PropertyCallbackInfo<v8::Value>& info,
+    v8::AccessorGetterCallback getter) {
+  // Leaving JavaScript.
+  Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate());
+  Address getter_address = reinterpret_cast<Address>(reinterpret_cast<intptr_t>(
+      getter));
+  VMState<EXTERNAL> state(isolate);
+  ExternalCallbackScope call_scope(isolate, getter_address);
+  return getter(property, info);
+}
+
+
+v8::Handle<v8::Value> InvokeInvocationCallback(
+    const v8::Arguments& args,
+    v8::InvocationCallback callback) {
+  Isolate* isolate = reinterpret_cast<Isolate*>(args.GetIsolate());
+  Address callback_address =
+      reinterpret_cast<Address>(reinterpret_cast<intptr_t>(callback));
+  VMState<EXTERNAL> state(isolate);
+  ExternalCallbackScope call_scope(isolate, callback_address);
+  return callback(args);
+}
+
+
+void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
+                            v8::FunctionCallback callback) {
+  Isolate* isolate = reinterpret_cast<Isolate*>(info.GetIsolate());
+  Address callback_address =
+      reinterpret_cast<Address>(reinterpret_cast<intptr_t>(callback));
+  VMState<EXTERNAL> state(isolate);
+  ExternalCallbackScope call_scope(isolate, callback_address);
+  return callback(info);
+}
+
+
 } }  // namespace v8::internal
index 3d1c69cb18662069fb385a2fdd7e02ba6fa26b7e..50d4b388cc47d3df1d7c82acef6f346b2479e953 100644 (file)
--- a/src/api.h
+++ b/src/api.h
@@ -680,6 +680,24 @@ void HandleScopeImplementer::DeleteExtensions(internal::Object** prev_limit) {
 }
 
 
+// Interceptor functions called from generated inline caches to notify
+// CPU profiler that external callbacks are invoked.
+v8::Handle<v8::Value> InvokeAccessorGetter(
+    v8::Local<v8::String> property,
+    const v8::AccessorInfo& info,
+    v8::AccessorGetter getter);
+
+
+void InvokeAccessorGetterCallback(
+    v8::Local<v8::String> property,
+    const v8::PropertyCallbackInfo<v8::Value>& info,
+    v8::AccessorGetterCallback getter);
+
+v8::Handle<v8::Value> InvokeInvocationCallback(const v8::Arguments& args,
+                                              v8::InvocationCallback callback);
+void InvokeFunctionCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
+                            v8::FunctionCallback callback);
+
 class Testing {
  public:
   static v8::Testing::StressType stress_type() { return stress_type_; }
index ee6eb97714217aab7672e66f02d05d65caa022af..52efd5fb522fe66fa70f1a623e572fbc8fd16af7 100644 (file)
@@ -6481,13 +6481,6 @@ void DirectCEntryStub::Generate(MacroAssembler* masm) {
 }
 
 
-void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
-                                    ExternalReference function) {
-  __ mov(r2, Operand(function));
-  GenerateCall(masm, r2);
-}
-
-
 void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
                                     Register target) {
   intptr_t code =
index 863848cc370d3009723971bb26b0ee40579e9898..1f663f52e9acf7a357b60485a39c45be2ee0b905 100644 (file)
@@ -585,7 +585,6 @@ class DirectCEntryStub: public PlatformCodeStub {
  public:
   DirectCEntryStub() {}
   void Generate(MacroAssembler* masm);
-  void GenerateCall(MacroAssembler* masm, ExternalReference function);
   void GenerateCall(MacroAssembler* masm, Register target);
 
  private:
index 4b6eac2974c1b6cdd11d017b5989e29ea678a56f..81a2d37643d2b018ae16d817559e0e9a0063214d 100644 (file)
@@ -2244,6 +2244,9 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
 
 
 void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
+                                              Address function_address,
+                                              ExternalReference thunk_ref,
+                                              Register thunk_last_arg,
                                               int stack_space,
                                               bool returns_handle,
                                               int return_value_offset) {
@@ -2274,11 +2277,31 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
     PopSafepointRegisters();
   }
 
+  ASSERT(!thunk_last_arg.is(r3));
+  Label profiler_disabled;
+  Label end_profiler_check;
+  bool* is_profiling_flag =
+      isolate()->cpu_profiler()->is_profiling_address();
+  STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
+  mov(r3, Operand(reinterpret_cast<int32_t>(is_profiling_flag)));
+  ldrb(r3, MemOperand(r3, 0));
+  cmp(r3, Operand(0));
+  b(eq, &profiler_disabled);
+
+  // Additional parameter is the address of the actual callback.
+  mov(thunk_last_arg, Operand(reinterpret_cast<int32_t>(function_address)));
+  mov(r3, Operand(thunk_ref));
+  jmp(&end_profiler_check);
+
+  bind(&profiler_disabled);
+  mov(r3, Operand(function));
+  bind(&end_profiler_check);
+
   // Native call returns to the DirectCEntry stub which redirects to the
   // return address pushed on stack (could have moved after GC).
   // DirectCEntry stub itself is generated early and never moves.
   DirectCEntryStub stub;
-  stub.GenerateCall(this, function);
+  stub.GenerateCall(this, r3);
 
   if (FLAG_log_timer_events) {
     FrameScope frame(this, StackFrame::MANUAL);
index 11d3066b91c0d2055c9f7746190861cf112baa92..8d3626dcaa4ebd8dffc70c10fff67004776718a2 100644 (file)
@@ -1085,6 +1085,9 @@ class MacroAssembler: public Assembler {
   // - space to be unwound on exit (includes the call JS arguments space and
   // the additional space allocated for the fast call).
   void CallApiFunctionAndReturn(ExternalReference function,
+                                Address function_address,
+                                ExternalReference thunk_ref,
+                                Register thunk_last_arg,
                                 int stack_space,
                                 bool returns_handle,
                                 int return_value_offset_from_fp);
index c9db167b0e66ff644a3aa09b7df7c54dfa23c792..a29d461ebf55acf87c008b56e2c2fa9b6a5712a1 100644 (file)
@@ -830,7 +830,10 @@ class Redirection {
     Isolate* isolate = Isolate::Current();
     Redirection* current = isolate->simulator_redirection();
     for (; current != NULL; current = current->next_) {
-      if (current->external_function_ == external_function) return current;
+      if (current->external_function_ == external_function) {
+        ASSERT_EQ(current->type(), type);
+        return current;
+      }
     }
     return new Redirection(external_function, type);
   }
@@ -1629,12 +1632,19 @@ typedef double (*SimulatorRuntimeFPIntCall)(double darg0, int32_t arg0);
 // (refer to InvocationCallback in v8.h).
 typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
 typedef void (*SimulatorRuntimeDirectApiCallNew)(int32_t arg0);
+typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingApiCall)(
+    int32_t arg0, int32_t arg1);
+typedef void (*SimulatorRuntimeProfilingApiCallNew)(int32_t arg0, int32_t arg1);
 
 // This signature supports direct call to accessor getter callback.
 typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0,
                                                                   int32_t arg1);
 typedef void (*SimulatorRuntimeDirectGetterCallNew)(int32_t arg0,
                                                     int32_t arg1);
+typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingGetterCall)(
+    int32_t arg0, int32_t arg1, int32_t arg2);
+typedef void (*SimulatorRuntimeProfilingGetterCallNew)(
+    int32_t arg0, int32_t arg1, int32_t arg2);
 
 // Software interrupt instructions are used by the simulator to call into the
 // C-based V8 runtime.
@@ -1798,6 +1808,31 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
               reinterpret_cast<SimulatorRuntimeDirectApiCallNew>(external);
           target(arg0);
         }
+      } else if (
+          redirection->type() == ExternalReference::PROFILING_API_CALL ||
+          redirection->type() == ExternalReference::PROFILING_API_CALL_NEW) {
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          PrintF("Call to host function at %p args %08x %08x",
+              reinterpret_cast<void*>(external), arg0, arg1);
+          if (!stack_aligned) {
+            PrintF(" with unaligned stack %08x\n", get_register(sp));
+          }
+          PrintF("\n");
+        }
+        CHECK(stack_aligned);
+        if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
+          SimulatorRuntimeProfilingApiCall target =
+              reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
+          v8::Handle<v8::Value> result = target(arg0, arg1);
+          if (::v8::internal::FLAG_trace_sim) {
+            PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
+          }
+          set_register(r0, reinterpret_cast<int32_t>(*result));
+        } else {
+          SimulatorRuntimeProfilingApiCallNew target =
+              reinterpret_cast<SimulatorRuntimeProfilingApiCallNew>(external);
+          target(arg0, arg1);
+        }
       } else if (
           redirection->type() == ExternalReference::DIRECT_GETTER_CALL ||
           redirection->type() == ExternalReference::DIRECT_GETTER_CALL_NEW) {
@@ -1823,6 +1858,32 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
               reinterpret_cast<SimulatorRuntimeDirectGetterCallNew>(external);
           target(arg0, arg1);
         }
+      } else if (
+          redirection->type() == ExternalReference::PROFILING_GETTER_CALL ||
+          redirection->type() == ExternalReference::PROFILING_GETTER_CALL_NEW) {
+        if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
+          PrintF("Call to host function at %p args %08x %08x %08x",
+              reinterpret_cast<void*>(external), arg0, arg1, arg2);
+          if (!stack_aligned) {
+            PrintF(" with unaligned stack %08x\n", get_register(sp));
+          }
+          PrintF("\n");
+        }
+        CHECK(stack_aligned);
+        if (redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
+          SimulatorRuntimeProfilingGetterCall target =
+              reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
+          v8::Handle<v8::Value> result = target(arg0, arg1, arg2);
+          if (::v8::internal::FLAG_trace_sim) {
+            PrintF("Returned %p\n", reinterpret_cast<void *>(*result));
+          }
+          set_register(r0, reinterpret_cast<int32_t>(*result));
+        } else {
+          SimulatorRuntimeProfilingGetterCallNew target =
+              reinterpret_cast<SimulatorRuntimeProfilingGetterCallNew>(
+                  external);
+          target(arg0, arg1, arg2);
+        }
       } else {
         // builtin call.
         ASSERT(redirection->type() == ExternalReference::BUILTIN_CALL);
@@ -1830,7 +1891,7 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
             reinterpret_cast<SimulatorRuntimeCall>(external);
         if (::v8::internal::FLAG_trace_sim || !stack_aligned) {
           PrintF(
-              "Call to host function at %p"
+              "Call to host function at %p "
               "args %08x, %08x, %08x, %08x, %08x, %08x",
               FUNCTION_ADDR(target),
               arg0,
index 1ccc10680a21f7944797a98452fd97923ee276ed..a0b23179d77a36d2dba5a372f1be5bd9b53a7946 100644 (file)
@@ -956,8 +956,22 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
   ExternalReference ref = ExternalReference(&fun,
                                             type,
                                             masm->isolate());
+  Address thunk_address = returns_handle
+      ? FUNCTION_ADDR(&InvokeInvocationCallback)
+      : FUNCTION_ADDR(&InvokeFunctionCallback);
+  ExternalReference::Type thunk_type =
+      returns_handle ?
+          ExternalReference::PROFILING_API_CALL :
+          ExternalReference::PROFILING_API_CALL_NEW;
+  ApiFunction thunk_fun(thunk_address);
+  ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
+      masm->isolate());
+
   AllowExternalCallThatCantCauseGC scope(masm);
   __ CallApiFunctionAndReturn(ref,
+                              function_address,
+                              thunk_ref,
+                              r1,
                               kStackUnwindSpace,
                               returns_handle,
                               kFastApiCallArguments + 1);
@@ -1454,14 +1468,28 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   Address getter_address = v8::ToCData<Address>(callback->getter());
   bool returns_handle =
       !CallbackTable::ReturnsVoid(isolate(), getter_address);
+
   ApiFunction fun(getter_address);
   ExternalReference::Type type =
       returns_handle ?
           ExternalReference::DIRECT_GETTER_CALL :
           ExternalReference::DIRECT_GETTER_CALL_NEW;
-
   ExternalReference ref = ExternalReference(&fun, type, isolate());
+
+  Address thunk_address = returns_handle
+      ? FUNCTION_ADDR(&InvokeAccessorGetter)
+      : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
+  ExternalReference::Type thunk_type =
+      returns_handle ?
+          ExternalReference::PROFILING_GETTER_CALL :
+          ExternalReference::PROFILING_GETTER_CALL_NEW;
+  ApiFunction thunk_fun(thunk_address);
+  ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
+      isolate());
   __ CallApiFunctionAndReturn(ref,
+                              getter_address,
+                              thunk_ref,
+                              r2,
                               kStackUnwindSpace,
                               returns_handle,
                               5);
index f66f8bfa7eb8495a400865bfecbb755d0f42587a..95853e8e3a3b0ae099797f047f66e07e5ce0b09e 100644 (file)
@@ -647,17 +647,35 @@ class ExternalReference BASE_EMBEDDED {
     // Handle<Value> f(v8::Arguments&)
     DIRECT_API_CALL,
 
+    // Call to invocation callback via InvokeInvocationCallback.
+    // Handle<Value> f(v8::Arguments&, v8::InvocationCallback)
+    PROFILING_API_CALL,
+
     // Direct call to API function callback.
     // void f(v8::Arguments&)
     DIRECT_API_CALL_NEW,
 
+    // Call to function callback via InvokeFunctionCallback.
+    // void f(v8::Arguments&, v8::FunctionCallback)
+    PROFILING_API_CALL_NEW,
+
     // Direct call to accessor getter callback.
     // Handle<value> f(Local<String> property, AccessorInfo& info)
     DIRECT_GETTER_CALL,
 
+    // Call to accessor getter callback via InvokeAccessorGetter.
+    // Handle<value> f(Local<String> property, AccessorInfo& info,
+    //     AccessorGetter getter)
+    PROFILING_GETTER_CALL,
+
     // Direct call to accessor getter callback.
     // void f(Local<String> property, AccessorInfo& info)
-    DIRECT_GETTER_CALL_NEW
+    DIRECT_GETTER_CALL_NEW,
+
+    // Call to accessor getter callback via InvokeAccessorGetterCallback.
+    // void f(Local<String> property, AccessorInfo& info,
+    //     AccessorGetterCallback callback)
+    PROFILING_GETTER_CALL_NEW
   };
 
   static void SetUp();
index 2f8479fccaa1cb1f53fe90bbefccd873a196600d..455c89332870caa7a2a87107d77890309e951057 100644 (file)
@@ -248,6 +248,9 @@ class CpuProfiler {
   void SharedFunctionInfoMoveEvent(Address from, Address to);
 
   INLINE(bool is_profiling() const) { return is_profiling_; }
+  bool* is_profiling_address() {
+    return &is_profiling_;
+  }
 
  private:
   void StartProcessorIfNotStarted();
index 60c5c2675f791a324d278cb2679b88fcdefd17db..17d4aac8add74eda4d6a69bc060427b26360b065 100644 (file)
@@ -1973,6 +1973,8 @@ void MacroAssembler::PrepareCallApiFunction(int argc, bool returns_handle) {
 
 
 void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
+                                              Address thunk_address,
+                                              Operand thunk_last_arg,
                                               int stack_space,
                                               bool returns_handle,
                                               int return_value_offset) {
@@ -1998,8 +2000,26 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
     PopSafepointRegisters();
   }
 
+
+  Label profiler_disabled;
+  Label end_profiler_check;
+  bool* is_profiling_flag =
+      isolate()->cpu_profiler()->is_profiling_address();
+  STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
+  mov(eax, Immediate(reinterpret_cast<Address>(is_profiling_flag)));
+  cmpb(Operand(eax, 0), 0);
+  j(zero, &profiler_disabled);
+
+  // Additional parameter is the address of the actual getter function.
+  mov(thunk_last_arg, Immediate(function_address));
+  // Call the api function.
+  call(thunk_address, RelocInfo::RUNTIME_ENTRY);
+  jmp(&end_profiler_check);
+
+  bind(&profiler_disabled);
   // Call the api function.
   call(function_address, RelocInfo::RUNTIME_ENTRY);
+  bind(&end_profiler_check);
 
   if (FLAG_log_timer_events) {
     FrameScope frame(this, StackFrame::MANUAL);
index 8380507ec0dbc0a5e496d157e2368f2ca7305f9e..7d780f0e11a51f39a94a45b6a5f97b94518b9d07 100644 (file)
@@ -784,6 +784,8 @@ class MacroAssembler: public Assembler {
   // caller-save registers.  Restores context.  On return removes
   // stack_space * kPointerSize (GCed).
   void CallApiFunctionAndReturn(Address function_address,
+                                Address thunk_address,
+                                Operand thunk_last_arg,
                                 int stack_space,
                                 bool returns_handle,
                                 int return_value_offset_from_ebp);
index 93923a70349b69e339fdac2c980703f09310b9ca..05995aa80161ec68cf05368243021eacd7f21763 100644 (file)
@@ -503,7 +503,12 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   STATIC_ASSERT(kFastApiCallArguments == 6);
   __ lea(eax, Operand(esp, kFastApiCallArguments * kPointerSize));
 
-  const int kApiArgc = 1;  // API function gets reference to the v8::Arguments.
+
+  // API function gets reference to the v8::Arguments. If CPU profiler
+  // is enabled wrapper function will be called and we need to pass
+  // address of the callback as additional parameter, always allocate
+  // space for it.
+  const int kApiArgc = 1 + 1;
 
   // Allocate the v8::Arguments structure in the arguments' space since
   // it's not controlled by GC.
@@ -517,20 +522,26 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   __ PrepareCallApiFunction(kApiArgc + kApiStackSpace, returns_handle);
 
   // v8::Arguments::implicit_args_.
-  __ mov(ApiParameterOperand(1, returns_handle), eax);
+  __ mov(ApiParameterOperand(2, returns_handle), eax);
   __ add(eax, Immediate(argc * kPointerSize));
   // v8::Arguments::values_.
-  __ mov(ApiParameterOperand(2, returns_handle), eax);
+  __ mov(ApiParameterOperand(3, returns_handle), eax);
   // v8::Arguments::length_.
-  __ Set(ApiParameterOperand(3, returns_handle), Immediate(argc));
+  __ Set(ApiParameterOperand(4, returns_handle), Immediate(argc));
   // v8::Arguments::is_construct_call_.
-  __ Set(ApiParameterOperand(4, returns_handle), Immediate(0));
+  __ Set(ApiParameterOperand(5, returns_handle), Immediate(0));
 
   // v8::InvocationCallback's argument.
-  __ lea(eax, ApiParameterOperand(1, returns_handle));
+  __ lea(eax, ApiParameterOperand(2, returns_handle));
   __ mov(ApiParameterOperand(0, returns_handle), eax);
 
+  Address thunk_address = returns_handle
+      ? FUNCTION_ADDR(&InvokeInvocationCallback)
+      : FUNCTION_ADDR(&InvokeFunctionCallback);
+
   __ CallApiFunctionAndReturn(function_address,
+                              thunk_address,
+                              ApiParameterOperand(1, returns_handle),
                               argc + kFastApiCallArguments + 1,
                               returns_handle,
                               kFastApiCallArguments + 1);
@@ -1406,7 +1417,9 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   // array for v8::Arguments::values_, handler for name and pointer
   // to the values (it considered as smi in GC).
   const int kStackSpace = PropertyCallbackArguments::kArgsLength + 2;
-  const int kApiArgc = 2;
+  // Allocate space for opional callback address parameter in case
+  // CPU profiler is active.
+  const int kApiArgc = 2 + 1;
 
   Address getter_address = v8::ToCData<Address>(callback->getter());
   bool returns_handle =
@@ -1422,7 +1435,13 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   // garbage collection but instead return the allocation failure
   // object.
 
+  Address thunk_address = returns_handle
+      ? FUNCTION_ADDR(&InvokeAccessorGetter)
+      : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
+
   __ CallApiFunctionAndReturn(getter_address,
+                              thunk_address,
+                              ApiParameterOperand(2, returns_handle),
                               kStackSpace,
                               returns_handle,
                               6);
index 5c8d08c5c6caad2a67bb65319a64a463d4bf7ce6..88d2bfe462e9ccc212750046f764c582ec10ca39 100644 (file)
@@ -6911,13 +6911,6 @@ void DirectCEntryStub::Generate(MacroAssembler* masm) {
 }
 
 
-void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
-                                    ExternalReference function) {
-  __ li(t9, Operand(function));
-  this->GenerateCall(masm, t9);
-}
-
-
 void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
                                     Register target) {
   __ Move(t9, target);
index ec7d147988f4a2f9c1189723b19db796574ff3f4..bf5db10f63b01efb125acc78d2088ca1f4ece1a0 100644 (file)
@@ -599,8 +599,6 @@ class DirectCEntryStub: public PlatformCodeStub {
  public:
   DirectCEntryStub() {}
   void Generate(MacroAssembler* masm);
-  void GenerateCall(MacroAssembler* masm,
-                                ExternalReference function);
   void GenerateCall(MacroAssembler* masm, Register target);
 
  private:
index 15436e7140b7834221394112263c65a12019dff0..d41ddd2ccf0592d16cc76b38f65130ca55c3550a 100644 (file)
@@ -3909,6 +3909,9 @@ static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
 
 
 void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
+                                              Address function_address,
+                                              ExternalReference thunk_ref,
+                                              Register thunk_last_arg,
                                               int stack_space,
                                               bool returns_handle,
                                               int return_value_offset_from_fp) {
@@ -3947,11 +3950,30 @@ void MacroAssembler::CallApiFunctionAndReturn(ExternalReference function,
     addiu(a0, fp, ExitFrameConstants::kStackSpaceOffset);
   }
 
+  Label profiler_disabled;
+  Label end_profiler_check;
+  bool* is_profiling_flag =
+      isolate()->cpu_profiler()->is_profiling_address();
+  STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
+  li(t9, reinterpret_cast<int32_t>(is_profiling_flag));
+  lb(t9, MemOperand(t9, 0));
+  beq(t9, zero_reg, &profiler_disabled);
+
+  // Third parameter is the address of the actual getter function.
+  li(thunk_last_arg, reinterpret_cast<int32_t>(function_address));
+  li(t9, Operand(thunk_ref));
+  jmp(&end_profiler_check);
+
+  bind(&profiler_disabled);
+  li(t9, Operand(function));
+
+  bind(&end_profiler_check);
+
   // Native call returns to the DirectCEntry stub which redirects to the
   // return address pushed on stack (could have moved after GC).
   // DirectCEntry stub itself is generated early and never moves.
   DirectCEntryStub stub;
-  stub.GenerateCall(this, function);
+  stub.GenerateCall(this, t9);
 
   if (FLAG_log_timer_events) {
     FrameScope frame(this, StackFrame::MANUAL);
index 5e6bfbae437a31e043c3c3c3a30253b14926466b..c983b8ba5a3f58ec41b5dfaa863043c953095eea 100644 (file)
@@ -1235,6 +1235,9 @@ class MacroAssembler: public Assembler {
   // - space to be unwound on exit (includes the call JS arguments space and
   // the additional space allocated for the fast call).
   void CallApiFunctionAndReturn(ExternalReference function,
+                                Address function_address,
+                                ExternalReference thunk_ref,
+                                Register thunk_last_arg,
                                 int stack_space,
                                 bool returns_handle,
                                 int return_value_offset_from_fp);
index d8a39ab30c764701e2d481f62c9affd3cd601f07..8771bd29f78367a7d28226de20a2525a7bd80cd9 100644 (file)
@@ -1394,6 +1394,9 @@ typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectApiCall)(int32_t arg0);
 // Here, we pass the first argument in a0, because this function
 // does not return a struct.
 typedef void (*SimulatorRuntimeDirectApiCallNew)(int32_t arg0);
+typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingApiCall)(
+    int32_t arg0, int32_t arg1);
+typedef void (*SimulatorRuntimeProfilingApiCallNew)(int32_t arg0, int32_t arg1);
 
 // This signature supports direct call to accessor getter callback.
 // See comment at SimulatorRuntimeDirectApiCall.
@@ -1402,6 +1405,10 @@ typedef v8::Handle<v8::Value> (*SimulatorRuntimeDirectGetterCall)(int32_t arg0,
 // See comment at SimulatorRuntimeDirectApiCallNew.
 typedef void (*SimulatorRuntimeDirectGetterCallNew)(int32_t arg0,
                                                     int32_t arg1);
+typedef v8::Handle<v8::Value> (*SimulatorRuntimeProfilingGetterCall)(
+    int32_t arg0, int32_t arg1, int32_t arg2);
+typedef void (*SimulatorRuntimeProfilingGetterCallNew)(
+    int32_t arg0, int32_t arg1, int32_t arg2);
 
 // Software interrupt instructions are used by the simulator to call into the
 // C-based V8 runtime. They are also used for debugging with simulator.
@@ -1570,6 +1577,30 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
             reinterpret_cast<SimulatorRuntimeDirectApiCallNew>(external);
         target(arg0);
       }
+    } else if (
+        redirection->type() == ExternalReference::PROFILING_API_CALL ||
+        redirection->type() == ExternalReference::PROFILING_API_CALL_NEW) {
+      if (redirection->type() == ExternalReference::PROFILING_API_CALL) {
+        // See comment at type definition of SimulatorRuntimeDirectApiCall
+        // for explanation of register usage.
+        if (::v8::internal::FLAG_trace_sim) {
+          PrintF("Call to host function at %p args %08x %08x\n",
+              reinterpret_cast<void*>(external), arg1, arg2);
+        }
+        SimulatorRuntimeProfilingApiCall target =
+            reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
+        v8::Handle<v8::Value> result = target(arg1, arg2);
+        *(reinterpret_cast<int*>(arg0)) = reinterpret_cast<int32_t>(*result);
+        set_register(v0, arg0);
+      } else {
+        if (::v8::internal::FLAG_trace_sim) {
+          PrintF("Call to host function at %p args %08x %08x\n",
+              reinterpret_cast<void*>(external), arg0, arg1);
+        }
+        SimulatorRuntimeProfilingApiCallNew target =
+            reinterpret_cast<SimulatorRuntimeProfilingApiCallNew>(external);
+        target(arg0, arg1);
+      }
     } else if (
         redirection->type() == ExternalReference::DIRECT_GETTER_CALL ||
         redirection->type() == ExternalReference::DIRECT_GETTER_CALL_NEW) {
@@ -1594,6 +1625,30 @@ void Simulator::SoftwareInterrupt(Instruction* instr) {
             reinterpret_cast<SimulatorRuntimeDirectGetterCallNew>(external);
         target(arg0, arg1);
       }
+    } else if (
+        redirection->type() == ExternalReference::PROFILING_GETTER_CALL ||
+        redirection->type() == ExternalReference::PROFILING_GETTER_CALL_NEW) {
+      if (redirection->type() == ExternalReference::PROFILING_GETTER_CALL) {
+        // See comment at type definition of SimulatorRuntimeProfilingGetterCall
+        // for explanation of register usage.
+        if (::v8::internal::FLAG_trace_sim) {
+          PrintF("Call to host function at %p args %08x %08x %08x\n",
+              reinterpret_cast<void*>(external), arg1, arg2, arg3);
+        }
+        SimulatorRuntimeProfilingGetterCall target =
+            reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(external);
+        v8::Handle<v8::Value> result = target(arg1, arg2, arg3);
+        *(reinterpret_cast<int*>(arg0)) = reinterpret_cast<int32_t>(*result);
+        set_register(v0, arg0);
+      } else {
+        if (::v8::internal::FLAG_trace_sim) {
+          PrintF("Call to host function at %p args %08x %08x %08x\n",
+              reinterpret_cast<void*>(external), arg0, arg1, arg2);
+        }
+        SimulatorRuntimeProfilingGetterCallNew target =
+            reinterpret_cast<SimulatorRuntimeProfilingGetterCallNew>(external);
+        target(arg0, arg1, arg2);
+      }
     } else {
       SimulatorRuntimeCall target =
                   reinterpret_cast<SimulatorRuntimeCall>(external);
index 6e422422ea6529984c4725e94b8ae15699d1620b..2f9e211bc6bacf05724ba4a5309197eb5f1407c5 100644 (file)
@@ -932,6 +932,7 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
       !CallbackTable::ReturnsVoid(masm->isolate(), function_address);
 
   Register first_arg = returns_handle ? a1 : a0;
+  Register second_arg = returns_handle ? a2 : a1;
 
   // first_arg = v8::Arguments&
   // Arguments is built at sp + 1 (sp is a reserved spot for ra).
@@ -958,8 +959,23 @@ static void GenerateFastApiDirectCall(MacroAssembler* masm,
       ExternalReference(&fun,
                         type,
                         masm->isolate());
+
+  Address thunk_address = returns_handle
+      ? FUNCTION_ADDR(&InvokeInvocationCallback)
+      : FUNCTION_ADDR(&InvokeFunctionCallback);
+  ExternalReference::Type thunk_type =
+      returns_handle ?
+          ExternalReference::PROFILING_API_CALL :
+          ExternalReference::PROFILING_API_CALL_NEW;
+  ApiFunction thunk_fun(thunk_address);
+  ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
+      masm->isolate());
+
   AllowExternalCallThatCantCauseGC scope(masm);
   __ CallApiFunctionAndReturn(ref,
+                              function_address,
+                              thunk_ref,
+                              second_arg,
                               kStackUnwindSpace,
                               returns_handle,
                               kFastApiCallArguments + 1);
@@ -1452,6 +1468,7 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
 
   Register first_arg = returns_handle ? a1 : a0;
   Register second_arg = returns_handle ? a2 : a1;
+  Register third_arg = returns_handle ? a3 : a2;
 
   __ mov(a2, scratch2());  // Saved in case scratch2 == a1.
   __ mov(first_arg, sp);  // (first argument - see note below) = Handle<Name>
@@ -1472,14 +1489,28 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   __ Addu(second_arg, sp, kPointerSize);
 
   const int kStackUnwindSpace = kFastApiCallArguments + 1;
+
   ApiFunction fun(getter_address);
   ExternalReference::Type type =
       returns_handle ?
           ExternalReference::DIRECT_GETTER_CALL :
           ExternalReference::DIRECT_GETTER_CALL_NEW;
-
   ExternalReference ref = ExternalReference(&fun, type, isolate());
+
+  Address thunk_address = returns_handle
+      ? FUNCTION_ADDR(&InvokeAccessorGetter)
+      : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
+  ExternalReference::Type thunk_type =
+      returns_handle ?
+          ExternalReference::PROFILING_GETTER_CALL :
+          ExternalReference::PROFILING_GETTER_CALL_NEW;
+  ApiFunction thunk_fun(thunk_address);
+  ExternalReference thunk_ref = ExternalReference(&thunk_fun, thunk_type,
+      isolate());
   __ CallApiFunctionAndReturn(ref,
+                              getter_address,
+                              thunk_ref,
+                              third_arg,
                               kStackUnwindSpace,
                               returns_handle,
                               5);
index efac288ee72c0870e5d1bee9b04290e94ac7ec1f..96b20f0369fbb472a8653700760e8e30d2dafb0b 100644 (file)
@@ -496,9 +496,7 @@ class SamplerThread : public Thread {
   void SampleContext(Sampler* sampler) {
     if (!SignalHandler::Installed()) return;
     pthread_t tid = sampler->platform_data()->vm_tid();
-    int result = pthread_kill(tid, SIGPROF);
-    USE(result);
-    ASSERT(result == 0);
+    pthread_kill(tid, SIGPROF);
   }
 
 #elif defined(__MACH__)
index a2568a400f41fa8960c61c8cda0998e03fa854f2..b6a1d34d6a5cbfc8af1a0e2dcfe1e0015860891e 100644 (file)
@@ -697,6 +697,8 @@ void MacroAssembler::PrepareCallApiFunction(int arg_stack_space,
 
 
 void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
+                                              Address thunk_address,
+                                              Register thunk_last_arg,
                                               int stack_space,
                                               bool returns_handle,
                                               int return_value_offset) {
@@ -737,9 +739,29 @@ void MacroAssembler::CallApiFunctionAndReturn(Address function_address,
     PopSafepointRegisters();
   }
 
+
+  Label profiler_disabled;
+  Label end_profiler_check;
+  bool* is_profiling_flag =
+      isolate()->cpu_profiler()->is_profiling_address();
+  STATIC_ASSERT(sizeof(*is_profiling_flag) == 1);
+  movq(rax, is_profiling_flag, RelocInfo::EXTERNAL_REFERENCE);
+  cmpb(Operand(rax, 0), Immediate(0));
+  j(zero, &profiler_disabled);
+
+  // Third parameter is the address of the actual getter function.
+  movq(thunk_last_arg, function_address, RelocInfo::EXTERNAL_REFERENCE);
+  movq(rax, thunk_address, RelocInfo::EXTERNAL_REFERENCE);
+  jmp(&end_profiler_check);
+
+  bind(&profiler_disabled);
   // Call the api function!
   movq(rax, reinterpret_cast<int64_t>(function_address),
        RelocInfo::EXTERNAL_REFERENCE);
+
+  bind(&end_profiler_check);
+
+  // Call the api function!
   call(rax);
 
   if (FLAG_log_timer_events) {
index 7b8747cab99457f26e71d258d14c0a826157bec6..1b7e586c0a04995584171c30939e19d1aa195e0a 100644 (file)
@@ -1239,6 +1239,8 @@ class MacroAssembler: public Assembler {
   // caller-save registers.  Restores context.  On return removes
   // stack_space * kPointerSize (GCed).
   void CallApiFunctionAndReturn(Address function_address,
+                                Address thunk_address,
+                                Register thunk_last_arg,
                                 int stack_space,
                                 bool returns_handle,
                                 int return_value_offset_from_rbp);
index c1059050ce16799d123f6d9dfececc37b58baade..2b1953e522d124bb6aa482633e676cd13629c087 100644 (file)
@@ -491,11 +491,14 @@ static void GenerateFastApiCall(MacroAssembler* masm,
 
 #if defined(__MINGW64__)
   Register arguments_arg = rcx;
+  Register callback_arg = rdx;
 #elif defined(_WIN64)
   // Win64 uses first register--rcx--for returned value.
   Register arguments_arg = returns_handle ? rdx : rcx;
+  Register callback_arg = returns_handle ? r8 : rdx;
 #else
   Register arguments_arg = rdi;
+  Register callback_arg = rsi;
 #endif
 
   // Allocate the v8::Arguments structure in the arguments' space since
@@ -514,7 +517,13 @@ static void GenerateFastApiCall(MacroAssembler* masm,
   // v8::InvocationCallback's argument.
   __ lea(arguments_arg, StackSpaceOperand(0));
 
+  Address thunk_address = returns_handle
+      ? FUNCTION_ADDR(&InvokeInvocationCallback)
+      : FUNCTION_ADDR(&InvokeFunctionCallback);
+
   __ CallApiFunctionAndReturn(function_address,
+                              thunk_address,
+                              callback_arg,
                               argc + kFastApiCallArguments + 1,
                               returns_handle,
                               kFastApiCallArguments + 1);
@@ -1318,13 +1327,16 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
       !CallbackTable::ReturnsVoid(isolate(), getter_address);
 
 #if defined(__MINGW64__)
+  Register getter_arg = r8;
   Register accessor_info_arg = rdx;
   Register name_arg = rcx;
 #elif defined(_WIN64)
   // Win64 uses first register--rcx--for returned value.
+  Register getter_arg = returns_handle ? r9 : r8;
   Register accessor_info_arg = returns_handle ? r8 : rdx;
   Register name_arg = returns_handle ? rdx : rcx;
 #else
+  Register getter_arg = rdx;
   Register accessor_info_arg = rsi;
   Register name_arg = rdi;
 #endif
@@ -1350,7 +1362,13 @@ void BaseLoadStubCompiler::GenerateLoadCallback(
   // could be used to pass arguments.
   __ lea(accessor_info_arg, StackSpaceOperand(0));
 
+  Address thunk_address = returns_handle
+      ? FUNCTION_ADDR(&InvokeAccessorGetter)
+      : FUNCTION_ADDR(&InvokeAccessorGetterCallback);
+
   __ CallApiFunctionAndReturn(getter_address,
+                              thunk_address,
+                              getter_arg,
                               kStackSpace,
                               returns_handle,
                               5);
index 5d38c211884ccbf82f00d085835caa01dca3e156..1318147f1b34a9e6587bcf6b26a88636b1993e47 100755 (executable)
@@ -804,7 +804,7 @@ THREADED_TEST(GlobalProperties) {
 
 
 template<typename T>
-static void CheckReturnValue(const T& t) {
+static void CheckReturnValue(const T& t, i::Address callback) {
   v8::ReturnValue<v8::Value> rv = t.GetReturnValue();
   i::Object** o = *reinterpret_cast<i::Object***>(&rv);
   CHECK_EQ(v8::Isolate::GetCurrent(), t.GetIsolate());
@@ -817,45 +817,70 @@ static void CheckReturnValue(const T& t) {
   rv.Set(v8::Handle<v8::Object>());
   CHECK((*o)->IsTheHole() || (*o)->IsUndefined());
   CHECK_EQ(is_runtime, (*o)->IsTheHole());
+
+  i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate());
+  // If CPU profiler is active check that when API callback is invoked
+  // VMState is set to EXTERNAL.
+  if (isolate->cpu_profiler()->is_profiling()) {
+    CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
+    CHECK(isolate->external_callback());
+    CHECK_EQ(callback, isolate->external_callback());
+  }
 }
 
-static v8::Handle<Value> handle_call(const v8::Arguments& args) {
+static v8::Handle<Value> handle_call_impl(
+    const v8::Arguments& args,
+    i::Address callback) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(args);
+  CheckReturnValue(args, callback);
   args.GetReturnValue().Set(v8_str("bad value"));
   return v8_num(102);
 }
 
+static v8::Handle<Value> handle_call(const v8::Arguments& args) {
+  return handle_call_impl(args, FUNCTION_ADDR(handle_call));
+}
+
 static v8::Handle<Value> handle_call_2(const v8::Arguments& args) {
-  return handle_call(args);
+  return handle_call_impl(args, FUNCTION_ADDR(handle_call_2));
 }
 
-static v8::Handle<Value> handle_call_indirect(const v8::Arguments& args) {
+static v8::Handle<Value> handle_call_indirect_impl(const v8::Arguments& args,
+                                                   i::Address callback) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(args);
+  CheckReturnValue(args, callback);
   args.GetReturnValue().Set(v8_str("bad value"));
   args.GetReturnValue().Set(v8_num(102));
   return v8::Handle<Value>();
 }
 
+static v8::Handle<Value> handle_call_indirect(const v8::Arguments& args) {
+  return handle_call_indirect_impl(args, FUNCTION_ADDR(handle_call_indirect));
+}
+
 static v8::Handle<Value> handle_call_indirect_2(const v8::Arguments& args) {
-  return handle_call_indirect(args);
+  return handle_call_indirect_impl(args, FUNCTION_ADDR(handle_call_indirect_2));
 }
 
-static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
+static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info,
+                                 i::Address callback) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(info);
+  CheckReturnValue(info, callback);
   info.GetReturnValue().Set(v8_str("bad value"));
   info.GetReturnValue().Set(v8_num(102));
 }
 
+static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) {
+  return handle_callback_impl(info, FUNCTION_ADDR(handle_callback));
+}
+
 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) {
-  return handle_callback(info);
+  return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2));
 }
 
 static v8::Handle<Value> construct_call(const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(args);
+  CheckReturnValue(args, FUNCTION_ADDR(construct_call));
   args.This()->Set(v8_str("x"), v8_num(1));
   args.This()->Set(v8_str("y"), v8_num(2));
   args.GetReturnValue().Set(v8_str("bad value"));
@@ -864,7 +889,7 @@ static v8::Handle<Value> construct_call(const v8::Arguments& args) {
 
 static v8::Handle<Value> construct_call_indirect(const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(args);
+  CheckReturnValue(args, FUNCTION_ADDR(construct_call_indirect));
   args.This()->Set(v8_str("x"), v8_num(1));
   args.This()->Set(v8_str("y"), v8_num(2));
   args.GetReturnValue().Set(v8_str("bad value"));
@@ -875,7 +900,7 @@ static v8::Handle<Value> construct_call_indirect(const v8::Arguments& args) {
 static void construct_callback(
     const v8::FunctionCallbackInfo<Value>& info) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(construct_callback));
   info.This()->Set(v8_str("x"), v8_num(1));
   info.This()->Set(v8_str("y"), v8_num(2));
   info.GetReturnValue().Set(v8_str("bad value"));
@@ -886,7 +911,7 @@ static void construct_callback(
 static v8::Handle<Value> Return239(
     Local<String> name, const AccessorInfo& info) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(Return239));
   info.GetReturnValue().Set(v8_str("bad value"));
   return v8_num(239);
 }
@@ -894,7 +919,7 @@ static v8::Handle<Value> Return239(
 static v8::Handle<Value> Return239Indirect(
     Local<String> name, const AccessorInfo& info) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(Return239Indirect));
   Handle<Value> value = v8_num(239);
   info.GetReturnValue().Set(v8_str("bad value"));
   info.GetReturnValue().Set(value);
@@ -904,7 +929,7 @@ static v8::Handle<Value> Return239Indirect(
 static void Return239Callback(
     Local<String> name, const v8::PropertyCallbackInfo<Value>& info) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(Return239Callback));
   info.GetReturnValue().Set(v8_str("bad value"));
   info.GetReturnValue().Set(v8_num(239));
 }
@@ -913,58 +938,97 @@ static void Return239Callback(
 template<typename Handler>
 static void TestFunctionTemplateInitializer(Handler handler,
                                             Handler handler_2) {
-  // Test constructor calls.
-  {
+  for (int i = 0; i < 2; i++) {
+    bool is_profiling = (i > 0);
+    // Test constructor calls.
+    {
+      LocalContext env;
+      v8::HandleScope scope(env->GetIsolate());
+
+      v8::Local<v8::String> profile_name = v8::String::New("my_profile1");
+      v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
+      if (is_profiling) {
+        cpu_profiler->StartCpuProfiling(profile_name);
+      }
+
+      Local<v8::FunctionTemplate> fun_templ =
+          v8::FunctionTemplate::New(handler);
+      Local<Function> fun = fun_templ->GetFunction();
+      env->Global()->Set(v8_str("obj"), fun);
+      Local<Script> script = v8_compile("obj()");
+      for (int i = 0; i < 30; i++) {
+        CHECK_EQ(102, script->Run()->Int32Value());
+      }
+
+      if (is_profiling) {
+        cpu_profiler->StopCpuProfiling(profile_name);
+      }
+    }
+    // Use SetCallHandler to initialize a function template, should work like
+    // the previous one.
+    {
+      LocalContext env;
+      v8::HandleScope scope(env->GetIsolate());
+
+      v8::Local<v8::String> profile_name = v8::String::New("my_profile2");
+      v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
+      if (is_profiling) {
+        cpu_profiler->StartCpuProfiling(profile_name);
+      }
+
+      Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
+      fun_templ->SetCallHandler(handler_2);
+      Local<Function> fun = fun_templ->GetFunction();
+      env->Global()->Set(v8_str("obj"), fun);
+      Local<Script> script = v8_compile("obj()");
+      for (int i = 0; i < 30; i++) {
+        CHECK_EQ(102, script->Run()->Int32Value());
+      }
+
+      if (is_profiling) {
+        cpu_profiler->DeleteAllCpuProfiles();
+      }
+    }
+  }
+}
+
+
+template<typename Constructor, typename Accessor>
+static void TestFunctionTemplateAccessor(Constructor constructor,
+                                         Accessor accessor) {
+  for (int i = 0; i < 2; i++) {
+    bool is_profiling = (i > 0);
     LocalContext env;
     v8::HandleScope scope(env->GetIsolate());
+
+    v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
+    if (is_profiling) {
+      v8::Local<v8::String> profile_name = v8::String::New("my_profile1");
+      cpu_profiler->StartCpuProfiling(profile_name);
+    }
+
     Local<v8::FunctionTemplate> fun_templ =
-        v8::FunctionTemplate::New(handler);
+        v8::FunctionTemplate::New(constructor);
+    fun_templ->SetClassName(v8_str("funky"));
+    fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
     Local<Function> fun = fun_templ->GetFunction();
     env->Global()->Set(v8_str("obj"), fun);
-    Local<Script> script = v8_compile("obj()");
+    Local<Value> result = v8_compile("(new obj()).toString()")->Run();
+    CHECK_EQ(v8_str("[object funky]"), result);
+    CompileRun("var obj_instance = new obj();");
+    Local<Script> script;
+    script = v8_compile("obj_instance.x");
     for (int i = 0; i < 30; i++) {
-      CHECK_EQ(102, script->Run()->Int32Value());
+      CHECK_EQ(1, script->Run()->Int32Value());
     }
-  }
-  // Use SetCallHandler to initialize a function template, should work like the
-  // previous one.
-  {
-    LocalContext env;
-    v8::HandleScope scope(env->GetIsolate());
-    Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
-    fun_templ->SetCallHandler(handler_2);
-    Local<Function> fun = fun_templ->GetFunction();
-    env->Global()->Set(v8_str("obj"), fun);
-    Local<Script> script = v8_compile("obj()");
+    script = v8_compile("obj_instance.m");
     for (int i = 0; i < 30; i++) {
-      CHECK_EQ(102, script->Run()->Int32Value());
+      CHECK_EQ(239, script->Run()->Int32Value());
     }
-  }
-}
 
-
-template<typename Constructor, typename Accessor>
-static void TestFunctionTemplateAccessor(Constructor constructor,
-                                         Accessor accessor) {
-  LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  Local<v8::FunctionTemplate> fun_templ =
-      v8::FunctionTemplate::New(constructor);
-  fun_templ->SetClassName(v8_str("funky"));
-  fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor);
-  Local<Function> fun = fun_templ->GetFunction();
-  env->Global()->Set(v8_str("obj"), fun);
-  Local<Value> result = v8_compile("(new obj()).toString()")->Run();
-  CHECK_EQ(v8_str("[object funky]"), result);
-  CompileRun("var obj_instance = new obj();");
-  Local<Script> script;
-  script = v8_compile("obj_instance.x");
-  for (int i = 0; i < 30; i++) {
-    CHECK_EQ(1, script->Run()->Int32Value());
-  }
-  script = v8_compile("obj_instance.m");
-  for (int i = 0; i < 30; i++) {
-    CHECK_EQ(239, script->Run()->Int32Value());
+    if (is_profiling) {
+      cpu_profiler->DeleteAllCpuProfiles();
+    }
   }
 }
 
@@ -982,41 +1046,55 @@ THREADED_TEST(FunctionTemplate) {
 
 static v8::Handle<v8::Value> SimpleDirectCallback(const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(args);
+  CheckReturnValue(args, FUNCTION_ADDR(SimpleDirectCallback));
   args.GetReturnValue().Set(v8_str("bad value"));
   return v8_num(51423 + args.Length());
 }
 
 static v8::Handle<v8::Value> SimpleIndirectCallback(const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(args);
+  CheckReturnValue(args, FUNCTION_ADDR(SimpleIndirectCallback));
   args.GetReturnValue().Set(v8_num(51423 + args.Length()));
   return v8::Handle<v8::Value>();
 }
 
 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback));
   info.GetReturnValue().Set(v8_num(51423 + info.Length()));
 }
 
 
 template<typename Callback>
 static void TestSimpleCallback(Callback callback) {
-  LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
-  object_template->Set("callback", v8::FunctionTemplate::New(callback));
-  v8::Local<v8::Object> object = object_template->NewInstance();
-  (*env)->Global()->Set(v8_str("callback_object"), object);
-  v8::Handle<v8::Script> script;
-  script = v8_compile("callback_object.callback(17)");
-  for (int i = 0; i < 30; i++) {
-    CHECK_EQ(51424, script->Run()->Int32Value());
-  }
-  script = v8_compile("callback_object.callback(17, 24)");
-  for (int i = 0; i < 30; i++) {
-    CHECK_EQ(51425, script->Run()->Int32Value());
+  for (int i = 0; i < 2; i++) {
+    bool is_profiling = i;
+    LocalContext env;
+    v8::HandleScope scope(env->GetIsolate());
+
+    v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler();
+    if (is_profiling) {
+      v8::Local<v8::String> profile_name = v8::String::New("my_profile1");
+      cpu_profiler->StartCpuProfiling(profile_name);
+    }
+
+    v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New();
+    object_template->Set("callback", v8::FunctionTemplate::New(callback));
+    v8::Local<v8::Object> object = object_template->NewInstance();
+    (*env)->Global()->Set(v8_str("callback_object"), object);
+    v8::Handle<v8::Script> script;
+    script = v8_compile("callback_object.callback(17)");
+    for (int i = 0; i < 30; i++) {
+      CHECK_EQ(51424, script->Run()->Int32Value());
+    }
+    script = v8_compile("callback_object.callback(17, 24)");
+    for (int i = 0; i < 30; i++) {
+      CHECK_EQ(51425, script->Run()->Int32Value());
+    }
+
+    if (is_profiling) {
+      cpu_profiler->DeleteAllCpuProfiles();
+    }
   }
 }
 
@@ -1048,35 +1126,35 @@ static bool fast_return_value_object_is_empty = false;
 template<>
 void FastReturnValueCallback<int32_t>(
     const v8::FunctionCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(FastReturnValueCallback<int32_t>));
   info.GetReturnValue().Set(fast_return_value_int32);
 }
 
 template<>
 void FastReturnValueCallback<uint32_t>(
     const v8::FunctionCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(FastReturnValueCallback<uint32_t>));
   info.GetReturnValue().Set(fast_return_value_uint32);
 }
 
 template<>
 void FastReturnValueCallback<double>(
     const v8::FunctionCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(FastReturnValueCallback<double>));
   info.GetReturnValue().Set(kFastReturnValueDouble);
 }
 
 template<>
 void FastReturnValueCallback<bool>(
     const v8::FunctionCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(FastReturnValueCallback<bool>));
   info.GetReturnValue().Set(fast_return_value_bool);
 }
 
 template<>
 void FastReturnValueCallback<void>(
     const v8::FunctionCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(FastReturnValueCallback<void>));
   switch (fast_return_value_void) {
     case kNullReturnValue:
       info.GetReturnValue().SetNull();
@@ -2053,7 +2131,7 @@ v8::Handle<v8::Object> bottom;
 static void CheckThisIndexedPropertyHandler(
     uint32_t index,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -2061,7 +2139,7 @@ static void CheckThisIndexedPropertyHandler(
 static void CheckThisNamedPropertyHandler(
     Local<String> name,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -2070,7 +2148,7 @@ void CheckThisIndexedPropertySetter(
     uint32_t index,
     Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -2080,7 +2158,7 @@ void CheckThisNamedPropertySetter(
     Local<String> property,
     Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -2088,7 +2166,7 @@ void CheckThisNamedPropertySetter(
 void CheckThisIndexedPropertyQuery(
     uint32_t index,
     const v8::PropertyCallbackInfo<v8::Integer>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -2097,7 +2175,7 @@ void CheckThisIndexedPropertyQuery(
 void CheckThisNamedPropertyQuery(
     Local<String> property,
     const v8::PropertyCallbackInfo<v8::Integer>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -2106,7 +2184,7 @@ void CheckThisNamedPropertyQuery(
 void CheckThisIndexedPropertyDeleter(
     uint32_t index,
     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -2115,7 +2193,7 @@ void CheckThisIndexedPropertyDeleter(
 void CheckThisNamedPropertyDeleter(
     Local<String> property,
     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -2123,7 +2201,7 @@ void CheckThisNamedPropertyDeleter(
 
 void CheckThisIndexedPropertyEnumerator(
     const v8::PropertyCallbackInfo<v8::Array>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -2131,7 +2209,7 @@ void CheckThisIndexedPropertyEnumerator(
 
 void CheckThisNamedPropertyEnumerator(
     const v8::PropertyCallbackInfo<v8::Array>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
 }
@@ -10637,7 +10715,7 @@ THREADED_TEST(InterceptorCallICCachedFromGlobal) {
 static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
                                                   const AccessorInfo& info) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
   int* call_count =
       reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value());
   ++(*call_count);
@@ -10650,7 +10728,7 @@ static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name,
 static v8::Handle<Value> FastApiCallback_TrivialSignature(
     const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(args);
+  CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature));
   v8::Isolate* isolate = v8::Isolate::GetCurrent();
   CHECK_EQ(isolate, args.GetIsolate());
   CHECK_EQ(args.This(), args.Holder());
@@ -10661,7 +10739,7 @@ static v8::Handle<Value> FastApiCallback_TrivialSignature(
 static v8::Handle<Value> FastApiCallback_SimpleSignature(
     const v8::Arguments& args) {
   ApiTestFuzzer::Fuzz();
-  CheckReturnValue(args);
+  CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature));
   v8::Isolate* isolate = v8::Isolate::GetCurrent();
   CHECK_EQ(isolate, args.GetIsolate());
   CHECK_EQ(args.This()->GetPrototype(), args.Holder());
@@ -10749,7 +10827,7 @@ static Handle<Value> DoDirectGetter() {
 
 static v8::Handle<v8::Value> DirectGetter(Local<String> name,
                                   const v8::AccessorInfo& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(DirectGetter));
   info.GetReturnValue().Set(v8_str("Garbage"));
   return DoDirectGetter();
 }
@@ -10757,7 +10835,7 @@ static v8::Handle<v8::Value> DirectGetter(Local<String> name,
 static v8::Handle<v8::Value> DirectGetterIndirect(
     Local<String> name,
     const v8::AccessorInfo& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(DirectGetterIndirect));
   info.GetReturnValue().Set(DoDirectGetter());
   return v8::Handle<v8::Value>();
 }
@@ -10765,7 +10843,7 @@ static v8::Handle<v8::Value> DirectGetterIndirect(
 static void DirectGetterCallback(
     Local<String> name,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
-  CheckReturnValue(info);
+  CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback));
   info.GetReturnValue().Set(DoDirectGetter());
 }
 
index a615fe954ef0a5f305f4612319ba603dad52ebb9..2184122717770be2eb0203fd9933394828e7f0e5 100644 (file)
@@ -802,9 +802,7 @@ TEST(NativeAccessorMonomorphicIC) {
 
   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   const v8::CpuProfileNode* startNode = GetChild(root, "start");
-  // TODO(yurys): in LoadIC should be changed to report external callback
-  // invocation. See r13768 where it was LoadCallbackProperty was removed.
-  // GetChild(startNode, "get foo");
+  GetChild(startNode, "get foo");
   GetChild(startNode, "set foo");
 
   cpu_profiler->DeleteAllCpuProfiles();
@@ -911,9 +909,8 @@ TEST(NativeMethodMonomorphicIC) {
 
   const v8::CpuProfileNode* root = profile->GetTopDownRoot();
   GetChild(root, "start");
-  // TODO(yurys): in CallIC should be changed to report external callback
-  // invocation.
-  // GetChild(startNode, "fooMethod");
+  const v8::CpuProfileNode* startNode = GetChild(root, "start");
+  GetChild(startNode, "fooMethod");
 
   cpu_profiler->DeleteAllCpuProfiles();
 }