Commit 73dbe9ac authored by Santiago Aboy Solanes's avatar Santiago Aboy Solanes Committed by Commit Bot

[codegen] Defer debug hook in InvokeFunctionCode

If we do the check in InvokeFunctionCode instead of doing it in
CheckDebugHook (now aptly named 'DebugHook'), we can defer the
debug hook to the end of InvokeFunctionCode and is to make the
common case stay in straight-line code.

Bug: v8:9771
Change-Id: Icff84e8ced9d120ae2fe293a391aaadd53441644
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1829219
Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: 's avatarDan Elphick <delphick@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64183}
parent f1c5be44
...@@ -1602,56 +1602,43 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, ...@@ -1602,56 +1602,43 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
} }
} }
void MacroAssembler::CheckDebugHook(Register fun, Register new_target, void MacroAssembler::CallDebugOnFunctionCall(Register fun, Register new_target,
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual) { const ParameterCount& actual) {
Label skip_hook; // Load receiver to pass it later to DebugOnFunctionCall hook.
if (actual.is_reg()) {
ExternalReference debug_hook_active = ldr(r4, MemOperand(sp, actual.reg(), LSL, kPointerSizeLog2));
ExternalReference::debug_hook_on_function_call_address(isolate()); } else {
Move(r4, debug_hook_active); ldr(r4, MemOperand(sp, actual.immediate() << kPointerSizeLog2));
ldrsb(r4, MemOperand(r4)); }
cmp(r4, Operand(0)); FrameScope frame(this, has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
b(eq, &skip_hook); if (expected.is_reg()) {
SmiTag(expected.reg());
{ Push(expected.reg());
// Load receiver to pass it later to DebugOnFunctionCall hook. }
if (actual.is_reg()) { if (actual.is_reg()) {
ldr(r4, MemOperand(sp, actual.reg(), LSL, kPointerSizeLog2)); SmiTag(actual.reg());
} else { Push(actual.reg());
ldr(r4, MemOperand(sp, actual.immediate() << kPointerSizeLog2)); }
} if (new_target.is_valid()) {
FrameScope frame(this, Push(new_target);
has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); }
if (expected.is_reg()) { Push(fun);
SmiTag(expected.reg()); Push(fun);
Push(expected.reg()); Push(r4);
} CallRuntime(Runtime::kDebugOnFunctionCall);
if (actual.is_reg()) { Pop(fun);
SmiTag(actual.reg()); if (new_target.is_valid()) {
Push(actual.reg()); Pop(new_target);
} }
if (new_target.is_valid()) { if (actual.is_reg()) {
Push(new_target); Pop(actual.reg());
} SmiUntag(actual.reg());
Push(fun); }
Push(fun); if (expected.is_reg()) {
Push(r4); Pop(expected.reg());
CallRuntime(Runtime::kDebugOnFunctionCall); SmiUntag(expected.reg());
Pop(fun);
if (new_target.is_valid()) {
Pop(new_target);
}
if (actual.is_reg()) {
Pop(actual.reg());
SmiUntag(actual.reg());
}
if (expected.is_reg()) {
Pop(expected.reg());
SmiUntag(expected.reg());
}
} }
bind(&skip_hook);
} }
void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
...@@ -1664,7 +1651,16 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, ...@@ -1664,7 +1651,16 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
DCHECK_IMPLIES(new_target.is_valid(), new_target == r3); DCHECK_IMPLIES(new_target.is_valid(), new_target == r3);
// On function call, call into the debugger if necessary. // On function call, call into the debugger if necessary.
CheckDebugHook(function, new_target, expected, actual); Label debug_hook, continue_after_hook;
{
ExternalReference debug_hook_active =
ExternalReference::debug_hook_on_function_call_address(isolate());
Move(r4, debug_hook_active);
ldrsb(r4, MemOperand(r4));
cmp(r4, Operand(0));
b(ne, &debug_hook);
}
bind(&continue_after_hook);
// Clear the new.target register if not given. // Clear the new.target register if not given.
if (!new_target.is_valid()) { if (!new_target.is_valid()) {
...@@ -1686,11 +1682,17 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, ...@@ -1686,11 +1682,17 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
DCHECK(flag == JUMP_FUNCTION); DCHECK(flag == JUMP_FUNCTION);
JumpCodeObject(code); JumpCodeObject(code);
} }
// Continue here if InvokePrologue does handle the invocation due to
// mismatched parameter counts.
bind(&done);
} }
b(&done);
// Deferred debug hook.
bind(&debug_hook);
CallDebugOnFunctionCall(function, new_target, expected, actual);
b(&continue_after_hook);
// Continue here if InvokePrologue does handle the invocation due to
// mismatched parameter counts.
bind(&done);
} }
void MacroAssembler::InvokeFunction(Register fun, Register new_target, void MacroAssembler::InvokeFunction(Register fun, Register new_target,
......
...@@ -633,10 +633,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { ...@@ -633,10 +633,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual, InvokeFlag flag); const ParameterCount& actual, InvokeFlag flag);
// On function call, call into the debugger if necessary. // On function call, call into the debugger.
void CheckDebugHook(Register fun, Register new_target, void CallDebugOnFunctionCall(Register fun, Register new_target,
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual); const ParameterCount& actual);
// Invoke the JavaScript function in the given register. Changes the // Invoke the JavaScript function in the given register. Changes the
// current context to the context in the function before invoking. // current context to the context in the function before invoking.
......
...@@ -2211,44 +2211,34 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, ...@@ -2211,44 +2211,34 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
Bind(&regular_invoke); Bind(&regular_invoke);
} }
void MacroAssembler::CheckDebugHook(Register fun, Register new_target, void MacroAssembler::CallDebugOnFunctionCall(Register fun, Register new_target,
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual) { const ParameterCount& actual) {
Label skip_hook; // Load receiver to pass it later to DebugOnFunctionCall hook.
if (actual.is_reg()) {
Mov(x4, ExternalReference::debug_hook_on_function_call_address(isolate())); Ldr(x4, MemOperand(sp, actual.reg(), LSL, kSystemPointerSizeLog2));
Ldrsb(x4, MemOperand(x4)); } else {
Cbz(x4, &skip_hook); Ldr(x4, MemOperand(sp, actual.immediate() << kSystemPointerSizeLog2));
}
{ FrameScope frame(this, has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
// Load receiver to pass it later to DebugOnFunctionCall hook.
if (actual.is_reg()) {
Ldr(x4, MemOperand(sp, actual.reg(), LSL, kSystemPointerSizeLog2));
} else {
Ldr(x4, MemOperand(sp, actual.immediate() << kSystemPointerSizeLog2));
}
FrameScope frame(this,
has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
Register expected_reg = padreg; Register expected_reg = padreg;
Register actual_reg = padreg; Register actual_reg = padreg;
if (expected.is_reg()) expected_reg = expected.reg(); if (expected.is_reg()) expected_reg = expected.reg();
if (actual.is_reg()) actual_reg = actual.reg(); if (actual.is_reg()) actual_reg = actual.reg();
if (!new_target.is_valid()) new_target = padreg; if (!new_target.is_valid()) new_target = padreg;
// Save values on stack. // Save values on stack.
SmiTag(expected_reg); SmiTag(expected_reg);
SmiTag(actual_reg); SmiTag(actual_reg);
Push(expected_reg, actual_reg, new_target, fun); Push(expected_reg, actual_reg, new_target, fun);
Push(fun, x4); Push(fun, x4);
CallRuntime(Runtime::kDebugOnFunctionCall); CallRuntime(Runtime::kDebugOnFunctionCall);
// Restore values from stack. // Restore values from stack.
Pop(fun, new_target, actual_reg, expected_reg); Pop(fun, new_target, actual_reg, expected_reg);
SmiUntag(actual_reg); SmiUntag(actual_reg);
SmiUntag(expected_reg); SmiUntag(expected_reg);
}
Bind(&skip_hook);
} }
void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
...@@ -2261,7 +2251,13 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, ...@@ -2261,7 +2251,13 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
DCHECK_IMPLIES(new_target.is_valid(), new_target.is(x3)); DCHECK_IMPLIES(new_target.is_valid(), new_target.is(x3));
// On function call, call into the debugger if necessary. // On function call, call into the debugger if necessary.
CheckDebugHook(function, new_target, expected, actual); Label debug_hook, continue_after_hook;
{
Mov(x4, ExternalReference::debug_hook_on_function_call_address(isolate()));
Ldrsb(x4, MemOperand(x4));
Cbnz(x4, &debug_hook);
}
bind(&continue_after_hook);
// Clear the new.target register if not given. // Clear the new.target register if not given.
if (!new_target.is_valid()) { if (!new_target.is_valid()) {
...@@ -2289,6 +2285,12 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, ...@@ -2289,6 +2285,12 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
JumpCodeObject(code); JumpCodeObject(code);
} }
} }
B(&done);
// Deferred debug hook.
bind(&debug_hook);
CallDebugOnFunctionCall(function, new_target, expected, actual);
B(&continue_after_hook);
// Continue here if InvokePrologue does handle the invocation due to // Continue here if InvokePrologue does handle the invocation due to
// mismatched parameter counts. // mismatched parameter counts.
......
...@@ -1770,10 +1770,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { ...@@ -1770,10 +1770,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
const ParameterCount& actual, Label* done, const ParameterCount& actual, Label* done,
InvokeFlag flag, bool* definitely_mismatches); InvokeFlag flag, bool* definitely_mismatches);
// On function call, call into the debugger if necessary. // On function call, call into the debugger.
void CheckDebugHook(Register fun, Register new_target, void CallDebugOnFunctionCall(Register fun, Register new_target,
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual); const ParameterCount& actual);
void InvokeFunctionCode(Register function, Register new_target, void InvokeFunctionCode(Register function, Register new_target,
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual, InvokeFlag flag); const ParameterCount& actual, InvokeFlag flag);
......
...@@ -1168,57 +1168,44 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, ...@@ -1168,57 +1168,44 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
} }
} }
void MacroAssembler::CheckDebugHook(Register fun, Register new_target, void MacroAssembler::CallDebugOnFunctionCall(Register fun, Register new_target,
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual) { const ParameterCount& actual) {
Label skip_hook; FrameScope frame(this, has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
if (expected.is_reg()) {
ExternalReference debug_hook_active = SmiTag(expected.reg());
ExternalReference::debug_hook_on_function_call_address(isolate()); Push(expected.reg());
push(eax); }
cmpb(ExternalReferenceAsOperand(debug_hook_active, eax), Immediate(0)); if (actual.is_reg()) {
pop(eax); SmiTag(actual.reg());
j(equal, &skip_hook); Push(actual.reg());
SmiUntag(actual.reg());
{ }
FrameScope frame(this, if (new_target.is_valid()) {
has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); Push(new_target);
if (expected.is_reg()) { }
SmiTag(expected.reg()); Push(fun);
Push(expected.reg()); Push(fun);
} Operand receiver_op =
if (actual.is_reg()) { actual.is_reg()
SmiTag(actual.reg()); ? Operand(ebp, actual.reg(), times_system_pointer_size,
Push(actual.reg()); kSystemPointerSize * 2)
SmiUntag(actual.reg()); : Operand(ebp, actual.immediate() * times_system_pointer_size +
} kSystemPointerSize * 2);
if (new_target.is_valid()) { Push(receiver_op);
Push(new_target); CallRuntime(Runtime::kDebugOnFunctionCall);
} Pop(fun);
Push(fun); if (new_target.is_valid()) {
Push(fun); Pop(new_target);
Operand receiver_op = }
actual.is_reg() if (actual.is_reg()) {
? Operand(ebp, actual.reg(), times_system_pointer_size, Pop(actual.reg());
kSystemPointerSize * 2) SmiUntag(actual.reg());
: Operand(ebp, actual.immediate() * times_system_pointer_size + }
kSystemPointerSize * 2); if (expected.is_reg()) {
Push(receiver_op); Pop(expected.reg());
CallRuntime(Runtime::kDebugOnFunctionCall); SmiUntag(expected.reg());
Pop(fun);
if (new_target.is_valid()) {
Pop(new_target);
}
if (actual.is_reg()) {
Pop(actual.reg());
SmiUntag(actual.reg());
}
if (expected.is_reg()) {
Pop(expected.reg());
SmiUntag(expected.reg());
}
} }
bind(&skip_hook);
} }
void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
...@@ -1233,7 +1220,16 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, ...@@ -1233,7 +1220,16 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
DCHECK_IMPLIES(actual.is_reg(), actual.reg() == eax); DCHECK_IMPLIES(actual.is_reg(), actual.reg() == eax);
// On function call, call into the debugger if necessary. // On function call, call into the debugger if necessary.
CheckDebugHook(function, new_target, expected, actual); Label debug_hook, continue_after_hook;
{
ExternalReference debug_hook_active =
ExternalReference::debug_hook_on_function_call_address(isolate());
push(eax);
cmpb(ExternalReferenceAsOperand(debug_hook_active, eax), Immediate(0));
pop(eax);
j(not_equal, &debug_hook, Label::kNear);
}
bind(&continue_after_hook);
// Clear the new.target register if not given. // Clear the new.target register if not given.
if (!new_target.is_valid()) { if (!new_target.is_valid()) {
...@@ -1256,8 +1252,15 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, ...@@ -1256,8 +1252,15 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
DCHECK(flag == JUMP_FUNCTION); DCHECK(flag == JUMP_FUNCTION);
JumpCodeObject(ecx); JumpCodeObject(ecx);
} }
bind(&done);
} }
jmp(&done, Label::kNear);
// Deferred debug hook.
bind(&debug_hook);
CallDebugOnFunctionCall(function, new_target, expected, actual);
jmp(&continue_after_hook, Label::kNear);
bind(&done);
} }
void MacroAssembler::InvokeFunction(Register fun, Register new_target, void MacroAssembler::InvokeFunction(Register fun, Register new_target,
......
...@@ -552,11 +552,11 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { ...@@ -552,11 +552,11 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual, InvokeFlag flag); const ParameterCount& actual, InvokeFlag flag);
// On function call, call into the debugger if necessary. // On function call, call into the debugger.
// This may clobber ecx. // This may clobber ecx.
void CheckDebugHook(Register fun, Register new_target, void CallDebugOnFunctionCall(Register fun, Register new_target,
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual); const ParameterCount& actual);
// Invoke the JavaScript function in the given register. Changes the // Invoke the JavaScript function in the given register. Changes the
// current context to the context in the function before invoking. // current context to the context in the function before invoking.
......
...@@ -2281,7 +2281,16 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, ...@@ -2281,7 +2281,16 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
DCHECK_IMPLIES(new_target.is_valid(), new_target == rdx); DCHECK_IMPLIES(new_target.is_valid(), new_target == rdx);
// On function call, call into the debugger if necessary. // On function call, call into the debugger if necessary.
CheckDebugHook(function, new_target, expected, actual); Label debug_hook, continue_after_hook;
{
ExternalReference debug_hook_active =
ExternalReference::debug_hook_on_function_call_address(isolate());
Operand debug_hook_active_operand =
ExternalReferenceAsOperand(debug_hook_active);
cmpb(debug_hook_active_operand, Immediate(0));
j(not_equal, &debug_hook, Label::kNear);
}
bind(&continue_after_hook);
// Clear the new.target register if not given. // Clear the new.target register if not given.
if (!new_target.is_valid()) { if (!new_target.is_valid()) {
...@@ -2305,8 +2314,15 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target, ...@@ -2305,8 +2314,15 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
DCHECK(flag == JUMP_FUNCTION); DCHECK(flag == JUMP_FUNCTION);
JumpCodeObject(rcx); JumpCodeObject(rcx);
} }
bind(&done);
} }
jmp(&done, Label::kNear);
// Deferred debug hook.
bind(&debug_hook);
CallDebugOnFunctionCall(function, new_target, expected, actual);
jmp(&continue_after_hook, Label::kNear);
bind(&done);
} }
void MacroAssembler::InvokePrologue(const ParameterCount& expected, void MacroAssembler::InvokePrologue(const ParameterCount& expected,
...@@ -2371,50 +2387,38 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected, ...@@ -2371,50 +2387,38 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
} }
} }
void MacroAssembler::CheckDebugHook(Register fun, Register new_target, void MacroAssembler::CallDebugOnFunctionCall(Register fun, Register new_target,
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual) { const ParameterCount& actual) {
Label skip_hook; FrameScope frame(this, has_frame() ? StackFrame::NONE : StackFrame::INTERNAL);
ExternalReference debug_hook_active = if (expected.is_reg()) {
ExternalReference::debug_hook_on_function_call_address(isolate()); SmiTag(expected.reg());
Operand debug_hook_active_operand = Push(expected.reg());
ExternalReferenceAsOperand(debug_hook_active); }
cmpb(debug_hook_active_operand, Immediate(0)); if (actual.is_reg()) {
j(equal, &skip_hook); SmiTag(actual.reg());
Push(actual.reg());
{ SmiUntag(actual.reg());
FrameScope frame(this, }
has_frame() ? StackFrame::NONE : StackFrame::INTERNAL); if (new_target.is_valid()) {
if (expected.is_reg()) { Push(new_target);
SmiTag(expected.reg()); }
Push(expected.reg()); Push(fun);
} Push(fun);
if (actual.is_reg()) { Push(StackArgumentsAccessor(rbp, actual).GetReceiverOperand());
SmiTag(actual.reg()); CallRuntime(Runtime::kDebugOnFunctionCall);
Push(actual.reg()); Pop(fun);
SmiUntag(actual.reg()); if (new_target.is_valid()) {
} Pop(new_target);
if (new_target.is_valid()) { }
Push(new_target); if (actual.is_reg()) {
} Pop(actual.reg());
Push(fun); SmiUntag(actual.reg());
Push(fun); }
Push(StackArgumentsAccessor(rbp, actual).GetReceiverOperand()); if (expected.is_reg()) {
CallRuntime(Runtime::kDebugOnFunctionCall); Pop(expected.reg());
Pop(fun); SmiUntag(expected.reg());
if (new_target.is_valid()) {
Pop(new_target);
}
if (actual.is_reg()) {
Pop(actual.reg());
SmiUntag(actual.reg());
}
if (expected.is_reg()) {
Pop(expected.reg());
SmiUntag(expected.reg());
}
} }
bind(&skip_hook);
} }
void TurboAssembler::StubPrologue(StackFrame::Type type) { void TurboAssembler::StubPrologue(StackFrame::Type type) {
......
...@@ -649,10 +649,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler { ...@@ -649,10 +649,10 @@ class V8_EXPORT_PRIVATE MacroAssembler : public TurboAssembler {
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual, InvokeFlag flag); const ParameterCount& actual, InvokeFlag flag);
// On function call, call into the debugger if necessary. // On function call, call into the debugger.
void CheckDebugHook(Register fun, Register new_target, void CallDebugOnFunctionCall(Register fun, Register new_target,
const ParameterCount& expected, const ParameterCount& expected,
const ParameterCount& actual); const ParameterCount& actual);
// Invoke the JavaScript function in the given register. Changes the // Invoke the JavaScript function in the given register. Changes the
// current context to the context in the function before invoking. // current context to the context in the function before invoking.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment