Removing redundant stub for runtime native calls.
Review URL: http://codereview.chromium.org/543207 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3745 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
8588518851
commit
9239bbdd91
@ -2286,7 +2286,8 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
|
|||||||
Comment cmnt(masm_, "[ DebuggerStatament");
|
Comment cmnt(masm_, "[ DebuggerStatament");
|
||||||
CodeForStatementPosition(node);
|
CodeForStatementPosition(node);
|
||||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||||
frame_->CallRuntime(Runtime::kDebugBreak, 0);
|
DebugerStatementStub ces;
|
||||||
|
frame_->CallStub(&ces, 0);
|
||||||
#endif
|
#endif
|
||||||
// Ignore the return value.
|
// Ignore the return value.
|
||||||
ASSERT(frame_->height() == original_height);
|
ASSERT(frame_->height() == original_height);
|
||||||
|
@ -98,7 +98,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
|
|||||||
__ mov(r0, Operand(0)); // no arguments
|
__ mov(r0, Operand(0)); // no arguments
|
||||||
__ mov(r1, Operand(ExternalReference::debug_break()));
|
__ mov(r1, Operand(ExternalReference::debug_break()));
|
||||||
|
|
||||||
CEntryDebugBreakStub ceb;
|
CEntryStub ceb(1);
|
||||||
__ CallStub(&ceb);
|
__ CallStub(&ceb);
|
||||||
|
|
||||||
// Restore the register values containing object pointers from the expression
|
// Restore the register values containing object pointers from the expression
|
||||||
|
@ -1035,9 +1035,13 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime::FunctionId function_id =
|
// TODO(1236192): Most runtime routines don't need the number of
|
||||||
static_cast<Runtime::FunctionId>(f->stub_id);
|
// arguments passed in because it is constant. At some point we
|
||||||
RuntimeStub stub(function_id, num_arguments);
|
// should remove this need and make the runtime routine entry code
|
||||||
|
// smarter.
|
||||||
|
mov(r0, Operand(num_arguments));
|
||||||
|
mov(r1, Operand(ExternalReference(f)));
|
||||||
|
CEntryStub stub(1);
|
||||||
CallStub(&stub);
|
CallStub(&stub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +55,9 @@ namespace internal {
|
|||||||
V(CounterOp) \
|
V(CounterOp) \
|
||||||
V(ArgumentsAccess) \
|
V(ArgumentsAccess) \
|
||||||
V(RegExpExec) \
|
V(RegExpExec) \
|
||||||
V(Runtime) \
|
|
||||||
V(CEntry) \
|
V(CEntry) \
|
||||||
V(JSEntry)
|
V(JSEntry) \
|
||||||
|
V(DebuggerStatement)
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -452,11 +452,6 @@ void CodeGenerator::CodeForSourcePosition(int pos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char* RuntimeStub::GetName() {
|
|
||||||
return Runtime::FunctionForId(id_)->stub_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char* GenericUnaryOpStub::GetName() {
|
const char* GenericUnaryOpStub::GetName() {
|
||||||
switch (op_) {
|
switch (op_) {
|
||||||
case Token::SUB:
|
case Token::SUB:
|
||||||
@ -474,14 +469,6 @@ const char* GenericUnaryOpStub::GetName() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RuntimeStub::Generate(MacroAssembler* masm) {
|
|
||||||
Runtime::Function* f = Runtime::FunctionForId(id_);
|
|
||||||
masm->TailCallRuntime(ExternalReference(f),
|
|
||||||
num_arguments_,
|
|
||||||
f->result_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
|
void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
|
||||||
switch (type_) {
|
switch (type_) {
|
||||||
case READ_LENGTH: GenerateReadLength(masm); break;
|
case READ_LENGTH: GenerateReadLength(masm); break;
|
||||||
@ -507,4 +494,10 @@ void ApiGetterEntryStub::SetCustomCache(Code* value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void DebugerStatementStub::Generate(MacroAssembler* masm) {
|
||||||
|
Runtime::Function* f = Runtime::FunctionForId(Runtime::kDebugBreak);
|
||||||
|
masm->TailCallRuntime(ExternalReference(f), 0, f->result_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
@ -181,43 +181,6 @@ class DeferredCode: public ZoneObject {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(DeferredCode);
|
DISALLOW_COPY_AND_ASSIGN(DeferredCode);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// RuntimeStub models code stubs calling entry points in the Runtime class.
|
|
||||||
class RuntimeStub : public CodeStub {
|
|
||||||
public:
|
|
||||||
explicit RuntimeStub(Runtime::FunctionId id, int num_arguments)
|
|
||||||
: id_(id), num_arguments_(num_arguments) { }
|
|
||||||
|
|
||||||
void Generate(MacroAssembler* masm);
|
|
||||||
|
|
||||||
// Disassembler support. It is useful to be able to print the name
|
|
||||||
// of the runtime function called through this stub.
|
|
||||||
static const char* GetNameFromMinorKey(int minor_key) {
|
|
||||||
return Runtime::FunctionForId(IdField::decode(minor_key))->stub_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Runtime::FunctionId id_;
|
|
||||||
int num_arguments_;
|
|
||||||
|
|
||||||
class ArgumentField: public BitField<int, 0, 16> {};
|
|
||||||
class IdField: public BitField<Runtime::FunctionId, 16, kMinorBits - 16> {};
|
|
||||||
|
|
||||||
Major MajorKey() { return Runtime; }
|
|
||||||
int MinorKey() {
|
|
||||||
return IdField::encode(id_) | ArgumentField::encode(num_arguments_);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* GetName();
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
void Print() {
|
|
||||||
PrintF("RuntimeStub (id %s)\n", Runtime::FunctionForId(id_)->name);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class StackCheckStub : public CodeStub {
|
class StackCheckStub : public CodeStub {
|
||||||
public:
|
public:
|
||||||
StackCheckStub() { }
|
StackCheckStub() { }
|
||||||
@ -422,16 +385,18 @@ class ApiGetterEntryStub : public CodeStub {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class CEntryDebugBreakStub : public CEntryStub {
|
// Mark the debugger statemet to be recognized bu debugger (by the MajorKey)
|
||||||
|
class DebugerStatementStub : public CodeStub {
|
||||||
public:
|
public:
|
||||||
CEntryDebugBreakStub() : CEntryStub(1) { }
|
DebugerStatementStub() { }
|
||||||
|
|
||||||
void Generate(MacroAssembler* masm) { GenerateBody(masm, true); }
|
void Generate(MacroAssembler* masm);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int MinorKey() { return 1; }
|
Major MajorKey() { return DebuggerStatement; }
|
||||||
|
int MinorKey() { return 0; }
|
||||||
|
|
||||||
const char* GetName() { return "CEntryDebugBreakStub"; }
|
const char* GetName() { return "DebugerStatementStub"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,9 +75,6 @@ BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
|
|||||||
BreakLocatorType type) {
|
BreakLocatorType type) {
|
||||||
debug_info_ = debug_info;
|
debug_info_ = debug_info;
|
||||||
type_ = type;
|
type_ = type;
|
||||||
// Get the stub early to avoid possible GC during iterations. We may need
|
|
||||||
// this stub to detect debugger calls generated from debugger statements.
|
|
||||||
debug_break_stub_ = RuntimeStub(Runtime::kDebugBreak, 0).GetCode();
|
|
||||||
reloc_iterator_ = NULL;
|
reloc_iterator_ = NULL;
|
||||||
reloc_iterator_original_ = NULL;
|
reloc_iterator_original_ = NULL;
|
||||||
Reset(); // Initialize the rest of the member variables.
|
Reset(); // Initialize the rest of the member variables.
|
||||||
@ -461,9 +458,7 @@ bool BreakLocationIterator::IsDebuggerStatement() {
|
|||||||
Code* code = Code::GetCodeFromTargetAddress(target);
|
Code* code = Code::GetCodeFromTargetAddress(target);
|
||||||
if (code->kind() == Code::STUB) {
|
if (code->kind() == Code::STUB) {
|
||||||
CodeStub::Major major_key = code->major_key();
|
CodeStub::Major major_key = code->major_key();
|
||||||
if (major_key == CodeStub::Runtime) {
|
return (major_key == CodeStub::DebuggerStatement);
|
||||||
return (*debug_break_stub_ == code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -132,7 +132,6 @@ class BreakLocationIterator {
|
|||||||
int position_;
|
int position_;
|
||||||
int statement_position_;
|
int statement_position_;
|
||||||
Handle<DebugInfo> debug_info_;
|
Handle<DebugInfo> debug_info_;
|
||||||
Handle<Code> debug_break_stub_;
|
|
||||||
RelocIterator* reloc_iterator_;
|
RelocIterator* reloc_iterator_;
|
||||||
RelocIterator* reloc_iterator_original_;
|
RelocIterator* reloc_iterator_original_;
|
||||||
|
|
||||||
|
@ -266,12 +266,6 @@ static int DecodeIt(FILE* f,
|
|||||||
case CodeStub::CallFunction:
|
case CodeStub::CallFunction:
|
||||||
out.AddFormatted("argc = %d", minor_key);
|
out.AddFormatted("argc = %d", minor_key);
|
||||||
break;
|
break;
|
||||||
case CodeStub::Runtime: {
|
|
||||||
const char* name =
|
|
||||||
RuntimeStub::GetNameFromMinorKey(minor_key);
|
|
||||||
out.AddFormatted("%s", name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
out.AddFormatted("minor: %d", minor_key);
|
out.AddFormatted("minor: %d", minor_key);
|
||||||
}
|
}
|
||||||
|
@ -998,7 +998,9 @@ void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
|
|||||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||||
Comment cmnt(masm_, "[ DebuggerStatement");
|
Comment cmnt(masm_, "[ DebuggerStatement");
|
||||||
SetStatementPosition(stmt);
|
SetStatementPosition(stmt);
|
||||||
__ CallRuntime(Runtime::kDebugBreak, 0);
|
|
||||||
|
DebugerStatementStub ces;
|
||||||
|
__ CallStub(&ces);
|
||||||
// Ignore the return value.
|
// Ignore the return value.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -1499,7 +1499,7 @@ void Heap::CreateRegExpCEntryStub() {
|
|||||||
|
|
||||||
|
|
||||||
void Heap::CreateCEntryDebugBreakStub() {
|
void Heap::CreateCEntryDebugBreakStub() {
|
||||||
CEntryDebugBreakStub stub;
|
DebugerStatementStub stub;
|
||||||
set_c_entry_debug_break_code(*stub.GetCode());
|
set_c_entry_debug_break_code(*stub.GetCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1526,7 +1526,7 @@ void Heap::CreateFixedStubs() {
|
|||||||
// { CEntryStub stub;
|
// { CEntryStub stub;
|
||||||
// c_entry_code_ = *stub.GetCode();
|
// c_entry_code_ = *stub.GetCode();
|
||||||
// }
|
// }
|
||||||
// { CEntryDebugBreakStub stub;
|
// { DebugerStatementStub stub;
|
||||||
// c_entry_debug_break_code_ = *stub.GetCode();
|
// c_entry_debug_break_code_ = *stub.GetCode();
|
||||||
// }
|
// }
|
||||||
// To workaround the problem, make separate functions without inlining.
|
// To workaround the problem, make separate functions without inlining.
|
||||||
|
@ -3901,7 +3901,9 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
|
|||||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||||
// Spill everything, even constants, to the frame.
|
// Spill everything, even constants, to the frame.
|
||||||
frame_->SpillAll();
|
frame_->SpillAll();
|
||||||
frame_->CallRuntime(Runtime::kDebugBreak, 0);
|
|
||||||
|
DebugerStatementStub ces;
|
||||||
|
frame_->CallStub(&ces, 0);
|
||||||
// Ignore the return value.
|
// Ignore the return value.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
|
|||||||
__ Set(eax, Immediate(0)); // no arguments
|
__ Set(eax, Immediate(0)); // no arguments
|
||||||
__ mov(ebx, Immediate(ExternalReference::debug_break()));
|
__ mov(ebx, Immediate(ExternalReference::debug_break()));
|
||||||
|
|
||||||
CEntryDebugBreakStub ceb;
|
CEntryStub ceb(1);
|
||||||
__ CallStub(&ceb);
|
__ CallStub(&ceb);
|
||||||
|
|
||||||
// Restore the register values containing object pointers from the expression
|
// Restore the register values containing object pointers from the expression
|
||||||
|
@ -1098,10 +1098,14 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime::FunctionId function_id =
|
// TODO(1236192): Most runtime routines don't need the number of
|
||||||
static_cast<Runtime::FunctionId>(f->stub_id);
|
// arguments passed in because it is constant. At some point we
|
||||||
RuntimeStub stub(function_id, num_arguments);
|
// should remove this need and make the runtime routine entry code
|
||||||
CallStub(&stub);
|
// smarter.
|
||||||
|
Set(eax, Immediate(num_arguments));
|
||||||
|
mov(ebx, Immediate(ExternalReference(f)));
|
||||||
|
CEntryStub ces(1);
|
||||||
|
CallStub(&ces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1114,10 +1118,14 @@ Object* MacroAssembler::TryCallRuntime(Runtime::Function* f,
|
|||||||
return Heap::undefined_value();
|
return Heap::undefined_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime::FunctionId function_id =
|
// TODO(1236192): Most runtime routines don't need the number of
|
||||||
static_cast<Runtime::FunctionId>(f->stub_id);
|
// arguments passed in because it is constant. At some point we
|
||||||
RuntimeStub stub(function_id, num_arguments);
|
// should remove this need and make the runtime routine entry code
|
||||||
return TryCallStub(&stub);
|
// smarter.
|
||||||
|
Set(eax, Immediate(num_arguments));
|
||||||
|
mov(ebx, Immediate(ExternalReference(f)));
|
||||||
|
CEntryStub ces(1);
|
||||||
|
return TryCallStub(&ces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -331,7 +331,7 @@ class MacroAssembler: public Assembler {
|
|||||||
// Eventually this should be used for all C calls.
|
// Eventually this should be used for all C calls.
|
||||||
void CallRuntime(Runtime::Function* f, int num_arguments);
|
void CallRuntime(Runtime::Function* f, int num_arguments);
|
||||||
|
|
||||||
// Call a runtime function, returning the RuntimeStub object called.
|
// Call a runtime function, returning the CodeStub object called.
|
||||||
// Try to generate the stub code if necessary. Do not perform a GC
|
// Try to generate the stub code if necessary. Do not perform a GC
|
||||||
// but instead return a retry after GC failure.
|
// but instead return a retry after GC failure.
|
||||||
Object* TryCallRuntime(Runtime::Function* f, int num_arguments);
|
Object* TryCallRuntime(Runtime::Function* f, int num_arguments);
|
||||||
|
@ -8130,12 +8130,12 @@ static Object* Runtime_IS_VAR(Arguments args) {
|
|||||||
// Implementation of Runtime
|
// Implementation of Runtime
|
||||||
|
|
||||||
#define F(name, nargs, ressize) \
|
#define F(name, nargs, ressize) \
|
||||||
{ #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
|
{ #name, FUNCTION_ADDR(Runtime_##name), nargs, \
|
||||||
static_cast<int>(Runtime::k##name), ressize },
|
static_cast<int>(Runtime::k##name), ressize },
|
||||||
|
|
||||||
static Runtime::Function Runtime_functions[] = {
|
static Runtime::Function Runtime_functions[] = {
|
||||||
RUNTIME_FUNCTION_LIST(F)
|
RUNTIME_FUNCTION_LIST(F)
|
||||||
{ NULL, NULL, NULL, 0, -1, 0 }
|
{ NULL, NULL, 0, -1, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef F
|
#undef F
|
||||||
|
@ -373,9 +373,6 @@ class Runtime : public AllStatic {
|
|||||||
// The JS name of the function.
|
// The JS name of the function.
|
||||||
const char* name;
|
const char* name;
|
||||||
|
|
||||||
// The name of the stub that calls the runtime function.
|
|
||||||
const char* stub_name;
|
|
||||||
|
|
||||||
// The C++ (native) entry point.
|
// The C++ (native) entry point.
|
||||||
byte* entry;
|
byte* entry;
|
||||||
|
|
||||||
|
@ -2212,7 +2212,9 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
|
|||||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||||
// Spill everything, even constants, to the frame.
|
// Spill everything, even constants, to the frame.
|
||||||
frame_->SpillAll();
|
frame_->SpillAll();
|
||||||
frame_->CallRuntime(Runtime::kDebugBreak, 0);
|
|
||||||
|
DebugerStatementStub ces;
|
||||||
|
frame_->CallStub(&ces, 0);
|
||||||
// Ignore the return value.
|
// Ignore the return value.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -7337,9 +7339,7 @@ int CEntryStub::MinorKey() {
|
|||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
// Simple results returned in rax (using default code).
|
// Simple results returned in rax (using default code).
|
||||||
// Complex results must be written to address passed as first argument.
|
// Complex results must be written to address passed as first argument.
|
||||||
// Use even numbers for minor keys, reserving the odd numbers for
|
return (result_size_ < 2) ? 0 : 1;
|
||||||
// CEntryDebugBreakStub.
|
|
||||||
return (result_size_ < 2) ? 0 : result_size_ * 2;
|
|
||||||
#else
|
#else
|
||||||
// Single results returned in rax (both AMD64 and Win64 calling conventions)
|
// Single results returned in rax (both AMD64 and Win64 calling conventions)
|
||||||
// and a struct of two pointers in rax+rdx (AMD64 calling convention only)
|
// and a struct of two pointers in rax+rdx (AMD64 calling convention only)
|
||||||
|
@ -68,7 +68,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
|
|||||||
__ xor_(rax, rax); // No arguments (argc == 0).
|
__ xor_(rax, rax); // No arguments (argc == 0).
|
||||||
__ movq(rbx, ExternalReference::debug_break());
|
__ movq(rbx, ExternalReference::debug_break());
|
||||||
|
|
||||||
CEntryDebugBreakStub ceb;
|
CEntryStub ceb(1);
|
||||||
__ CallStub(&ceb);
|
__ CallStub(&ceb);
|
||||||
|
|
||||||
// Restore the register values containing object pointers from the expression
|
// Restore the register values containing object pointers from the expression
|
||||||
|
@ -344,10 +344,14 @@ void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Runtime::FunctionId function_id =
|
// TODO(1236192): Most runtime routines don't need the number of
|
||||||
static_cast<Runtime::FunctionId>(f->stub_id);
|
// arguments passed in because it is constant. At some point we
|
||||||
RuntimeStub stub(function_id, num_arguments);
|
// should remove this need and make the runtime routine entry code
|
||||||
CallStub(&stub);
|
// smarter.
|
||||||
|
movq(rax, Immediate(num_arguments));
|
||||||
|
movq(rbx, ExternalReference(f));
|
||||||
|
CEntryStub ces(f->result_size);
|
||||||
|
CallStub(&ces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2047,6 +2047,33 @@ TEST(DebuggerStatement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Test setting a breakpoint on the debugger statement.
|
||||||
|
TEST(DebuggerStatementBreakpoint) {
|
||||||
|
break_point_hit_count = 0;
|
||||||
|
v8::HandleScope scope;
|
||||||
|
DebugLocalContext env;
|
||||||
|
v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
|
||||||
|
v8::Undefined());
|
||||||
|
v8::Script::Compile(v8::String::New("function foo(){debugger;}"))->Run();
|
||||||
|
v8::Local<v8::Function> foo =
|
||||||
|
v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
|
||||||
|
|
||||||
|
// The debugger statement triggers breakpint hit
|
||||||
|
foo->Call(env->Global(), 0, NULL);
|
||||||
|
CHECK_EQ(1, break_point_hit_count);
|
||||||
|
|
||||||
|
int bp = SetBreakPoint(foo, 0);
|
||||||
|
|
||||||
|
// Set breakpoint does not duplicate hits
|
||||||
|
foo->Call(env->Global(), 0, NULL);
|
||||||
|
CHECK_EQ(2, break_point_hit_count);
|
||||||
|
|
||||||
|
ClearBreakPoint(bp);
|
||||||
|
v8::Debug::SetDebugEventListener(NULL);
|
||||||
|
CheckDebuggerUnloaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Thest that the evaluation of expressions when a break point is hit generates
|
// Thest that the evaluation of expressions when a break point is hit generates
|
||||||
// the correct results.
|
// the correct results.
|
||||||
TEST(DebugEvaluate) {
|
TEST(DebugEvaluate) {
|
||||||
|
Loading…
Reference in New Issue
Block a user