[ia32,root] Port all CallFunction variants

As part of this, we also update all InvokeFunctionCode callers to pass
ecx as the expected-argc register.

Drive-by: Inline InvokeFunction overload into its single use.

Bug: v8:6666
Change-Id: I67590ecc3f4981d014642c9e18d3ed6db9831e54
Reviewed-on: https://chromium-review.googlesource.com/1233653
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56040}
This commit is contained in:
Jakob Gruber 2018-09-19 13:25:48 +02:00 committed by Commit Bot
parent 15b7c38969
commit 23cf68ac2c
5 changed files with 33 additions and 32 deletions

View File

@ -17,15 +17,24 @@ namespace internal {
void Builtins::Generate_CallFunction_ReceiverIsNullOrUndefined(
MacroAssembler* masm) {
#ifdef V8_TARGET_ARCH_IA32
Assembler::SupportsRootRegisterScope supports_root_register(masm);
#endif
Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined);
}
void Builtins::Generate_CallFunction_ReceiverIsNotNullOrUndefined(
MacroAssembler* masm) {
#ifdef V8_TARGET_ARCH_IA32
Assembler::SupportsRootRegisterScope supports_root_register(masm);
#endif
Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined);
}
void Builtins::Generate_CallFunction_ReceiverIsAny(MacroAssembler* masm) {
#ifdef V8_TARGET_ARCH_IA32
Assembler::SupportsRootRegisterScope supports_root_register(masm);
#endif
Generate_CallFunction(masm, ConvertReceiverMode::kAny);
}

View File

@ -1866,6 +1866,8 @@ void Builtins::Generate_CallOrConstructForwardVarargs(MacroAssembler* masm,
// static
void Builtins::Generate_CallFunction(MacroAssembler* masm,
ConvertReceiverMode mode) {
Assembler::SupportsRootRegisterScope supports_root_register(masm);
// ----------- S t a t e -------------
// -- eax : the number of arguments (not including the receiver)
// -- edi : the function to call (checked to be a JSFunction)
@ -1906,8 +1908,10 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
__ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
__ JumpIfSmi(ecx, &convert_to_object, Label::kNear);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ebx);
__ CmpObjectType(ecx, FIRST_JS_RECEIVER_TYPE, ecx); // Clobbers ecx.
__ j(above_equal, &done_convert);
// Reload the receiver (it was clobbered by CmpObjectType).
__ mov(ecx, Operand(esp, eax, times_pointer_size, kPointerSize));
if (mode != ConvertReceiverMode::kNotNullOrUndefined) {
Label convert_global_proxy;
__ JumpIfRoot(ecx, Heap::kUndefinedValueRootIndex,
@ -1955,9 +1959,9 @@ void Builtins::Generate_CallFunction(MacroAssembler* masm,
// -----------------------------------
__ movzx_w(
ebx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
ecx, FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount actual(eax);
ParameterCount expected(ebx);
ParameterCount expected(ecx);
__ InvokeFunctionCode(edi, no_reg, expected, actual, JUMP_FUNCTION);
// The function is a "classConstructor", need to raise an exception.
__ bind(&class_constructor);

View File

@ -40,11 +40,13 @@ void DebugCodegen::GenerateFrameDropperTrampoline(MacroAssembler* masm) {
__ movzx_w(
eax, FieldOperand(eax, SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount dummy(eax);
__ InvokeFunction(edi, dummy, dummy, JUMP_FUNCTION);
// The expected and actual argument counts don't matter as long as they match
// and we don't enter the ArgumentsAdaptorTrampoline.
ParameterCount dummy(0);
__ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
__ InvokeFunctionCode(edi, no_reg, dummy, dummy, JUMP_FUNCTION);
}
const bool LiveEdit::kFrameDropperSupported = true;
#undef __

View File

@ -1037,6 +1037,9 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
bool* definitely_mismatches,
InvokeFlag flag,
Label::Distance done_near) {
DCHECK_IMPLIES(expected.is_reg(), expected.reg() == ecx);
DCHECK_IMPLIES(actual.is_reg(), actual.reg() == eax);
bool definitely_matches = false;
*definitely_mismatches = false;
Label invoke;
@ -1055,7 +1058,7 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
definitely_matches = true;
} else {
*definitely_mismatches = true;
mov(ebx, expected.immediate());
mov(ecx, expected.immediate());
}
}
} else {
@ -1066,14 +1069,14 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
mov(eax, actual.immediate());
cmp(expected.reg(), actual.immediate());
j(equal, &invoke);
DCHECK(expected.reg() == ebx);
DCHECK(expected.reg() == ecx);
} else if (expected.reg() != actual.reg()) {
// Both expected and actual are in (different) registers. This
// is the case when we invoke functions using call and apply.
cmp(expected.reg(), actual.reg());
j(equal, &invoke);
DCHECK(actual.reg() == eax);
DCHECK(expected.reg() == ebx);
DCHECK(expected.reg() == ecx);
} else {
definitely_matches = true;
Move(eax, actual.reg());
@ -1081,9 +1084,6 @@ void MacroAssembler::InvokePrologue(const ParameterCount& expected,
}
if (!definitely_matches) {
// TODO(v8:6666): All call-sites should be updated to pass in ecx as the
// expected register to avoid this useless move.
MoveForRootRegisterRefactoring(ecx, ebx);
Handle<Code> adaptor = BUILTIN_CODE(isolate(), ArgumentsAdaptorTrampoline);
if (flag == CALL_FUNCTION) {
Call(adaptor, RelocInfo::CODE_TARGET);
@ -1155,6 +1155,8 @@ void MacroAssembler::InvokeFunctionCode(Register function, Register new_target,
DCHECK(flag == JUMP_FUNCTION || has_frame());
DCHECK(function == edi);
DCHECK_IMPLIES(new_target.is_valid(), new_target == edx);
DCHECK_IMPLIES(expected.is_reg(), expected.reg() == ecx);
DCHECK_IMPLIES(actual.is_reg(), actual.reg() == eax);
// On function call, call into the debugger if necessary.
CheckDebugHook(function, new_target, expected, actual);
@ -1192,28 +1194,15 @@ void MacroAssembler::InvokeFunction(Register fun, Register new_target,
DCHECK(flag == JUMP_FUNCTION || has_frame());
DCHECK(fun == edi);
mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
mov(ecx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
movzx_w(ebx,
FieldOperand(ebx, SharedFunctionInfo::kFormalParameterCountOffset));
movzx_w(ecx,
FieldOperand(ecx, SharedFunctionInfo::kFormalParameterCountOffset));
ParameterCount expected(ebx);
ParameterCount expected(ecx);
InvokeFunctionCode(edi, new_target, expected, actual, flag);
}
void MacroAssembler::InvokeFunction(Register fun,
const ParameterCount& expected,
const ParameterCount& actual,
InvokeFlag flag) {
// You can't call a function without a valid frame.
DCHECK(flag == JUMP_FUNCTION || has_frame());
DCHECK(fun == edi);
mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
InvokeFunctionCode(edi, no_reg, expected, actual, flag);
}
void MacroAssembler::LoadGlobalProxy(Register dst) {
mov(dst, NativeContextOperand());
mov(dst, ContextOperand(dst, Context::GLOBAL_PROXY_INDEX));

View File

@ -608,9 +608,6 @@ class MacroAssembler : public TurboAssembler {
void InvokeFunction(Register function, Register new_target,
const ParameterCount& actual, InvokeFlag flag);
void InvokeFunction(Register function, const ParameterCount& expected,
const ParameterCount& actual, InvokeFlag flag);
// Compare object type for heap object.
// Incoming register is heap_object and outgoing register is map.
void CmpObjectType(Register heap_object, InstanceType type, Register map);