Revert 12069: Implements a new API to set a function entry hook for profiling
Reverted due to waterfall failures TBR=mstarzinger@chromium.org Review URL: https://chromiumcodereview.appspot.com/10704189 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12070 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
d6edbdd436
commit
30569cba9b
40
include/v8.h
40
include/v8.h
@ -2915,33 +2915,15 @@ typedef bool (*EntropySource)(unsigned char* buffer, size_t length);
|
|||||||
* resolving the location of a return address on the stack. Profilers that
|
* resolving the location of a return address on the stack. Profilers that
|
||||||
* change the return address on the stack can use this to resolve the stack
|
* change the return address on the stack can use this to resolve the stack
|
||||||
* location to whereever the profiler stashed the original return address.
|
* location to whereever the profiler stashed the original return address.
|
||||||
*
|
* When invoked, return_addr_location will point to a location on stack where
|
||||||
* \param return_addr_location points to a location on stack where a machine
|
* a machine return address resides, this function should return either the
|
||||||
* return address resides.
|
* same pointer, or a pointer to the profiler's copy of the original return
|
||||||
* \returns either return_addr_location, or else a pointer to the profiler's
|
* address.
|
||||||
* copy of the original return address.
|
|
||||||
*
|
|
||||||
* \note the resolver function must not cause garbage collection.
|
|
||||||
*/
|
*/
|
||||||
typedef uintptr_t (*ReturnAddressLocationResolver)(
|
typedef uintptr_t (*ReturnAddressLocationResolver)(
|
||||||
uintptr_t return_addr_location);
|
uintptr_t return_addr_location);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FunctionEntryHook is the type of the profile entry hook called at entry to
|
|
||||||
* any generated function when function-level profiling is enabled.
|
|
||||||
*
|
|
||||||
* \param function the address of the function that's being entered.
|
|
||||||
* \param return_addr_location points to a location on stack where the machine
|
|
||||||
* return address resides. This can be used to identify the caller of
|
|
||||||
* \p function, and/or modified to divert execution when \p function exits.
|
|
||||||
*
|
|
||||||
* \note the entry hook must not cause garbage collection.
|
|
||||||
*/
|
|
||||||
typedef void (*FunctionEntryHook)(uintptr_t function,
|
|
||||||
uintptr_t return_addr_location);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for iterating though all external resources in the heap.
|
* Interface for iterating though all external resources in the heap.
|
||||||
*/
|
*/
|
||||||
@ -3202,20 +3184,6 @@ class V8EXPORT V8 {
|
|||||||
static void SetReturnAddressLocationResolver(
|
static void SetReturnAddressLocationResolver(
|
||||||
ReturnAddressLocationResolver return_address_resolver);
|
ReturnAddressLocationResolver return_address_resolver);
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows the host application to provide the address of a function that's
|
|
||||||
* invoked on entry to every V8-generated function.
|
|
||||||
* Note that \p entry_hook is invoked at the very start of each
|
|
||||||
* generated function.
|
|
||||||
*
|
|
||||||
* \param entry_hook a function that will be invoked on entry to every
|
|
||||||
* V8-generated function.
|
|
||||||
* \returns true on success on supported platforms, false on failure.
|
|
||||||
* \note Setting a new entry hook function when one is already active will
|
|
||||||
* fail.
|
|
||||||
*/
|
|
||||||
static bool SetFunctionEntryHook(FunctionEntryHook entry_hook);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjusts the amount of registered external memory. Used to give
|
* Adjusts the amount of registered external memory. Used to give
|
||||||
* V8 an indication of the amount of externally allocated memory
|
* V8 an indication of the amount of externally allocated memory
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include "../include/v8-profiler.h"
|
#include "../include/v8-profiler.h"
|
||||||
#include "../include/v8-testing.h"
|
#include "../include/v8-testing.h"
|
||||||
#include "bootstrapper.h"
|
#include "bootstrapper.h"
|
||||||
#include "code-stubs.h"
|
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
#include "conversions-inl.h"
|
#include "conversions-inl.h"
|
||||||
#include "counters.h"
|
#include "counters.h"
|
||||||
@ -4233,11 +4232,6 @@ void v8::V8::SetReturnAddressLocationResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool v8::V8::SetFunctionEntryHook(FunctionEntryHook entry_hook) {
|
|
||||||
return i::ProfileEntryHookStub::SetFunctionEntryHook(entry_hook);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool v8::V8::Dispose() {
|
bool v8::V8::Dispose() {
|
||||||
i::Isolate* isolate = i::Isolate::Current();
|
i::Isolate* isolate = i::Isolate::Current();
|
||||||
if (!ApiCheck(isolate != NULL && isolate->IsDefaultIsolate(),
|
if (!ApiCheck(isolate != NULL && isolate->IsDefaultIsolate(),
|
||||||
|
@ -7513,63 +7513,6 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
|
|||||||
__ Ret();
|
__ Ret();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
|
|
||||||
if (entry_hook_ != NULL) {
|
|
||||||
ProfileEntryHookStub stub;
|
|
||||||
__ push(lr);
|
|
||||||
__ CallStub(&stub);
|
|
||||||
__ pop(lr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
|
|
||||||
// The entry hook is a "push lr" instruction, followed by a call.
|
|
||||||
const int32_t kReturnAddressDistanceFromFunctionStart =
|
|
||||||
Assembler::kCallTargetAddressOffset + Assembler::kInstrSize;
|
|
||||||
|
|
||||||
// Save live volatile registers.
|
|
||||||
__ Push(lr, r5, r1);
|
|
||||||
const int32_t kNumSavedRegs = 3;
|
|
||||||
|
|
||||||
// Compute the function's address for the first argument.
|
|
||||||
__ sub(r0, lr, Operand(kReturnAddressDistanceFromFunctionStart));
|
|
||||||
|
|
||||||
// The caller's return address is above the saved temporaries.
|
|
||||||
// Grab that for the second argument to the hook.
|
|
||||||
__ add(r1, sp, Operand(kNumSavedRegs * kPointerSize));
|
|
||||||
|
|
||||||
// Align the stack if necessary.
|
|
||||||
int frame_alignment = masm->ActivationFrameAlignment();
|
|
||||||
if (frame_alignment > kPointerSize) {
|
|
||||||
__ mov(r5, sp);
|
|
||||||
ASSERT(IsPowerOf2(frame_alignment));
|
|
||||||
__ and_(sp, sp, Operand(-frame_alignment));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(V8_HOST_ARCH_ARM)
|
|
||||||
__ mov(ip, Operand(reinterpret_cast<int32_t>(&entry_hook_)));
|
|
||||||
__ ldr(ip, MemOperand(ip));
|
|
||||||
#else
|
|
||||||
// Under the simulator we need to indirect the entry hook through a
|
|
||||||
// trampoline function at a known address.
|
|
||||||
ApiFunction dispatcher(reinterpret_cast<Address>(EntryHookTrampoline));
|
|
||||||
__ mov(ip, Operand(ExternalReference(&dispatcher,
|
|
||||||
ExternalReference::BUILTIN_CALL,
|
|
||||||
masm->isolate())));
|
|
||||||
#endif
|
|
||||||
__ Call(ip);
|
|
||||||
|
|
||||||
// Restore the stack pointer if needed.
|
|
||||||
if (frame_alignment > kPointerSize) {
|
|
||||||
__ mov(sp, r5);
|
|
||||||
}
|
|
||||||
|
|
||||||
__ Pop(lr, r5, r1);
|
|
||||||
__ Ret();
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
@ -134,8 +134,6 @@ void FullCodeGenerator::Generate() {
|
|||||||
SetFunctionPosition(function());
|
SetFunctionPosition(function());
|
||||||
Comment cmnt(masm_, "[ function compiled by full code generator");
|
Comment cmnt(masm_, "[ function compiled by full code generator");
|
||||||
|
|
||||||
ProfileEntryHookStub::MaybeCallEntryHook(masm_);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (strlen(FLAG_stop_at) > 0 &&
|
if (strlen(FLAG_stop_at) > 0 &&
|
||||||
info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
||||||
|
@ -127,8 +127,6 @@ void LCodeGen::Comment(const char* format, ...) {
|
|||||||
bool LCodeGen::GeneratePrologue() {
|
bool LCodeGen::GeneratePrologue() {
|
||||||
ASSERT(is_generating());
|
ASSERT(is_generating());
|
||||||
|
|
||||||
ProfileEntryHookStub::MaybeCallEntryHook(masm_);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (strlen(FLAG_stop_at) > 0 &&
|
if (strlen(FLAG_stop_at) > 0 &&
|
||||||
info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
||||||
|
@ -470,26 +470,4 @@ void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
|
|||||||
KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
|
KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FunctionEntryHook ProfileEntryHookStub::entry_hook_ = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
void ProfileEntryHookStub::EntryHookTrampoline(intptr_t function,
|
|
||||||
intptr_t stack_pointer) {
|
|
||||||
if (entry_hook_ != NULL)
|
|
||||||
entry_hook_(function, stack_pointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool ProfileEntryHookStub::SetFunctionEntryHook(FunctionEntryHook entry_hook) {
|
|
||||||
// We don't allow setting a new entry hook over one that's
|
|
||||||
// already active, as the hooks won't stack.
|
|
||||||
if (entry_hook != 0 && entry_hook_ != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
entry_hook_ = entry_hook;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
@ -73,8 +73,7 @@ namespace internal {
|
|||||||
V(DebuggerStatement) \
|
V(DebuggerStatement) \
|
||||||
V(StringDictionaryLookup) \
|
V(StringDictionaryLookup) \
|
||||||
V(ElementsTransitionAndStore) \
|
V(ElementsTransitionAndStore) \
|
||||||
V(StoreArrayLiteralElement) \
|
V(StoreArrayLiteralElement)
|
||||||
V(ProfileEntryHook)
|
|
||||||
|
|
||||||
// List of code stubs only used on ARM platforms.
|
// List of code stubs only used on ARM platforms.
|
||||||
#ifdef V8_TARGET_ARCH_ARM
|
#ifdef V8_TARGET_ARCH_ARM
|
||||||
@ -1143,37 +1142,6 @@ class StoreArrayLiteralElementStub : public CodeStub {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(StoreArrayLiteralElementStub);
|
DISALLOW_COPY_AND_ASSIGN(StoreArrayLiteralElementStub);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ProfileEntryHookStub : public CodeStub {
|
|
||||||
public:
|
|
||||||
explicit ProfileEntryHookStub() {}
|
|
||||||
|
|
||||||
// The profile entry hook function is not allowed to cause a GC.
|
|
||||||
virtual bool SometimesSetsUpAFrame() { return false; }
|
|
||||||
|
|
||||||
// Generates a call to the entry hook if it's enabled.
|
|
||||||
static void MaybeCallEntryHook(MacroAssembler* masm);
|
|
||||||
|
|
||||||
// Sets or unsets the entry hook function. Returns true on success,
|
|
||||||
// false on an attempt to replace a non-NULL entry hook with another
|
|
||||||
// non-NULL hook.
|
|
||||||
static bool SetFunctionEntryHook(FunctionEntryHook entry_hook);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void EntryHookTrampoline(intptr_t function,
|
|
||||||
intptr_t stack_pointer);
|
|
||||||
|
|
||||||
Major MajorKey() { return ProfileEntryHook; }
|
|
||||||
int MinorKey() { return 0; }
|
|
||||||
|
|
||||||
void Generate(MacroAssembler* masm);
|
|
||||||
|
|
||||||
// The current function entry hook.
|
|
||||||
static FunctionEntryHook entry_hook_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(ProfileEntryHookStub);
|
|
||||||
};
|
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
|
||||||
#endif // V8_CODE_STUBS_H_
|
#endif // V8_CODE_STUBS_H_
|
||||||
|
@ -7474,38 +7474,6 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
|
|||||||
__ ret(0);
|
__ ret(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
|
|
||||||
if (entry_hook_ != NULL) {
|
|
||||||
ProfileEntryHookStub stub;
|
|
||||||
masm->CallStub(&stub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
|
|
||||||
// Ecx is the only volatile register we must save.
|
|
||||||
__ push(ecx);
|
|
||||||
|
|
||||||
// Calculate and push the original stack pointer.
|
|
||||||
__ lea(eax, Operand(esp, kPointerSize));
|
|
||||||
__ push(eax);
|
|
||||||
|
|
||||||
// Calculate and push the function address.
|
|
||||||
__ mov(eax, Operand(eax, 0));
|
|
||||||
__ sub(eax, Immediate(Assembler::kCallInstructionLength));
|
|
||||||
__ push(eax);
|
|
||||||
|
|
||||||
// Call the entry hook.
|
|
||||||
int32_t hook_location = reinterpret_cast<int32_t>(&entry_hook_);
|
|
||||||
__ call(Operand(hook_location, RelocInfo::NONE));
|
|
||||||
__ add(esp, Immediate(2 * kPointerSize));
|
|
||||||
|
|
||||||
// Restore ecx.
|
|
||||||
__ pop(ecx);
|
|
||||||
__ ret(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
@ -123,8 +123,6 @@ void FullCodeGenerator::Generate() {
|
|||||||
SetFunctionPosition(function());
|
SetFunctionPosition(function());
|
||||||
Comment cmnt(masm_, "[ function compiled by full code generator");
|
Comment cmnt(masm_, "[ function compiled by full code generator");
|
||||||
|
|
||||||
ProfileEntryHookStub::MaybeCallEntryHook(masm_);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (strlen(FLAG_stop_at) > 0 &&
|
if (strlen(FLAG_stop_at) > 0 &&
|
||||||
info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
||||||
@ -4552,6 +4550,7 @@ FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
|
|||||||
return previous_;
|
return previous_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
@ -135,8 +135,6 @@ void LCodeGen::Comment(const char* format, ...) {
|
|||||||
bool LCodeGen::GeneratePrologue() {
|
bool LCodeGen::GeneratePrologue() {
|
||||||
ASSERT(is_generating());
|
ASSERT(is_generating());
|
||||||
|
|
||||||
ProfileEntryHookStub::MaybeCallEntryHook(masm_);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (strlen(FLAG_stop_at) > 0 &&
|
if (strlen(FLAG_stop_at) > 0 &&
|
||||||
info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
||||||
|
@ -6420,40 +6420,6 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
|
|||||||
__ ret(0);
|
__ ret(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
|
|
||||||
if (entry_hook_ != NULL) {
|
|
||||||
ProfileEntryHookStub stub;
|
|
||||||
masm->CallStub(&stub);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
|
|
||||||
// RCX is the only volatile register we must save.
|
|
||||||
__ push(rcx);
|
|
||||||
|
|
||||||
// Calculate the original stack pointer and store it in RDX, the second arg.
|
|
||||||
__ lea(rdx, Operand(rsp, kPointerSize));
|
|
||||||
|
|
||||||
// Calculate the function address to RCX, the first arg.
|
|
||||||
__ movq(rcx, Operand(rdx, 0));
|
|
||||||
__ subq(rcx, Immediate(Assembler::kShortCallInstructionLength));
|
|
||||||
|
|
||||||
// Reserve stack for the first 4 args.
|
|
||||||
__ subq(rsp, Immediate(4 * kPointerSize));
|
|
||||||
|
|
||||||
// Call the entry hook.
|
|
||||||
int64_t hook_location = reinterpret_cast<int64_t>(&entry_hook_);
|
|
||||||
__ movq(rax, hook_location, RelocInfo::NONE);
|
|
||||||
__ call(Operand(rax, 0));
|
|
||||||
__ addq(rsp, Immediate(4 * kPointerSize));
|
|
||||||
|
|
||||||
// Restore RCX.
|
|
||||||
__ pop(rcx);
|
|
||||||
__ ret(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
@ -123,8 +123,6 @@ void FullCodeGenerator::Generate() {
|
|||||||
SetFunctionPosition(function());
|
SetFunctionPosition(function());
|
||||||
Comment cmnt(masm_, "[ function compiled by full code generator");
|
Comment cmnt(masm_, "[ function compiled by full code generator");
|
||||||
|
|
||||||
ProfileEntryHookStub::MaybeCallEntryHook(masm_);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (strlen(FLAG_stop_at) > 0 &&
|
if (strlen(FLAG_stop_at) > 0 &&
|
||||||
info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
||||||
|
@ -128,8 +128,6 @@ void LCodeGen::Comment(const char* format, ...) {
|
|||||||
bool LCodeGen::GeneratePrologue() {
|
bool LCodeGen::GeneratePrologue() {
|
||||||
ASSERT(is_generating());
|
ASSERT(is_generating());
|
||||||
|
|
||||||
ProfileEntryHookStub::MaybeCallEntryHook(masm_);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (strlen(FLAG_stop_at) > 0 &&
|
if (strlen(FLAG_stop_at) > 0 &&
|
||||||
info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
info_->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include "isolate.h"
|
#include "isolate.h"
|
||||||
#include "compilation-cache.h"
|
#include "compilation-cache.h"
|
||||||
#include "execution.h"
|
#include "execution.h"
|
||||||
#include "objects.h"
|
|
||||||
#include "snapshot.h"
|
#include "snapshot.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
@ -10874,110 +10873,6 @@ THREADED_TEST(NestedHandleScopeAndContexts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static i::Handle<i::JSFunction>* foo_ptr = NULL;
|
|
||||||
static int foo_count = 0;
|
|
||||||
static i::Handle<i::JSFunction>* bar_ptr = NULL;
|
|
||||||
static int bar_count = 0;
|
|
||||||
|
|
||||||
|
|
||||||
static void entry_hook(uintptr_t function,
|
|
||||||
uintptr_t return_addr_location) {
|
|
||||||
i::Code* code = i::Code::GetCodeFromTargetAddress(
|
|
||||||
reinterpret_cast<i::Address>(function));
|
|
||||||
CHECK(code != NULL);
|
|
||||||
|
|
||||||
if (bar_ptr != NULL && code == (*bar_ptr)->code())
|
|
||||||
++bar_count;
|
|
||||||
|
|
||||||
if (foo_ptr != NULL && code == (*foo_ptr)->code())
|
|
||||||
++foo_count;
|
|
||||||
|
|
||||||
// TODO(siggi): Verify return_addr_location.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void RunLoopInNewEnv() {
|
|
||||||
bar_ptr = NULL;
|
|
||||||
foo_ptr = NULL;
|
|
||||||
|
|
||||||
v8::HandleScope outer;
|
|
||||||
v8::Persistent<Context> env = Context::New();
|
|
||||||
env->Enter();
|
|
||||||
|
|
||||||
const char* script =
|
|
||||||
"function bar() {"
|
|
||||||
" var sum = 0;"
|
|
||||||
" for (i = 0; i < 100; ++i)"
|
|
||||||
" sum = foo(i);"
|
|
||||||
" return sum;"
|
|
||||||
"}"
|
|
||||||
"function foo(i) { return i * i; }";
|
|
||||||
CompileRun(script);
|
|
||||||
i::Handle<i::JSFunction> bar =
|
|
||||||
i::Handle<i::JSFunction>::cast(
|
|
||||||
v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))));
|
|
||||||
ASSERT(*bar);
|
|
||||||
|
|
||||||
i::Handle<i::JSFunction> foo =
|
|
||||||
i::Handle<i::JSFunction>::cast(
|
|
||||||
v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))));
|
|
||||||
ASSERT(*foo);
|
|
||||||
|
|
||||||
bar_ptr = &bar;
|
|
||||||
foo_ptr = &foo;
|
|
||||||
|
|
||||||
v8::Handle<v8::Value> value = CompileRun("bar();");
|
|
||||||
CHECK(value->IsNumber());
|
|
||||||
CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
|
|
||||||
|
|
||||||
// Test the optimized codegen path.
|
|
||||||
value = CompileRun("%OptimizeFunctionOnNextCall(foo);"
|
|
||||||
"bar();");
|
|
||||||
CHECK(value->IsNumber());
|
|
||||||
CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value());
|
|
||||||
|
|
||||||
env->Exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
THREADED_TEST(SetFunctionEntryHook) {
|
|
||||||
i::FLAG_allow_natives_syntax = true;
|
|
||||||
|
|
||||||
// Test setting and resetting the entry hook.
|
|
||||||
// Nulling it should always succeed.
|
|
||||||
CHECK(v8::V8::SetFunctionEntryHook(NULL));
|
|
||||||
|
|
||||||
CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
|
|
||||||
// Setting a hook while one's active should fail.
|
|
||||||
CHECK_EQ(false, v8::V8::SetFunctionEntryHook(entry_hook));
|
|
||||||
|
|
||||||
CHECK(v8::V8::SetFunctionEntryHook(NULL));
|
|
||||||
|
|
||||||
// Reset the entry count to zero and set the entry hook.
|
|
||||||
bar_count = 0;
|
|
||||||
foo_count = 0;
|
|
||||||
CHECK(v8::V8::SetFunctionEntryHook(entry_hook));
|
|
||||||
RunLoopInNewEnv();
|
|
||||||
|
|
||||||
CHECK_EQ(2, bar_count);
|
|
||||||
CHECK_EQ(200, foo_count);
|
|
||||||
|
|
||||||
// Clear the entry hook and count.
|
|
||||||
bar_count = 0;
|
|
||||||
foo_count = 0;
|
|
||||||
v8::V8::SetFunctionEntryHook(NULL);
|
|
||||||
|
|
||||||
// Clear the compilation cache to make sure we don't reuse the
|
|
||||||
// functions from the previous invocation.
|
|
||||||
v8::internal::Isolate::Current()->compilation_cache()->Clear();
|
|
||||||
|
|
||||||
// Verify that entry hooking is now disabled.
|
|
||||||
RunLoopInNewEnv();
|
|
||||||
CHECK(0u == bar_count);
|
|
||||||
CHECK(0u == foo_count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
|
static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); }
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user